home *** CD-ROM | disk | FTP | other *** search
/ Aminet 2 / Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso / Aminet / text / print / ghostscript2_6_1.lha / amiga-src / gdevamiga.c < prev    next >
C/C++ Source or Header  |  1993-07-25  |  110KB  |  5,239 lines

  1. /* Copyright (C) 1992 Aladdin Enterprises.  All rights reserved.
  2.    Distributed by Free Software Foundation, Inc.
  3.  
  4. This file is part of Ghostscript.
  5.  
  6. Ghostscript is distributed in the hope that it will be useful, but
  7. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  8. to anyone for the consequences of using it or for whether it serves any
  9. particular purpose or works at all, unless he says so in writing.  Refer
  10. to the Ghostscript General Public License for full details.
  11.  
  12. Everyone is granted permission to copy, modify and redistribute
  13. Ghostscript, but only under the conditions described in the Ghostscript
  14. General Public License.  A copy of this license is supposed to have been
  15. given to you along with Ghostscript so you can know your rights and
  16. responsibilities.  It should be in a file named COPYING.  Among other
  17. things, the copyright notice and this notice must be preserved on all
  18. copies.  */
  19.  
  20. /* gdevamiga.c */
  21. /* Amiga driver for Ghostscript library, requires Kickstart 2.04 or higher */
  22.  
  23. /* Written by Olaf `Olsen' Barthel, last change 25 July 1993
  24.  *
  25.  * My address:   Olaf Barthel
  26.  *               Brabeckstrasse 35
  27.  *             D-30559 Hannover
  28.  *
  29.  *      eMail:   olsen@sourcery.han.de
  30.  */
  31.  
  32. #include <intuition/intuitionbase.h>
  33. #include <intuition/gadgetclass.h>
  34. #include <intuition/imageclass.h>
  35. #include <intuition/icclass.h>
  36. #include <graphics/displayinfo.h>
  37. #include <libraries/iffparse.h>
  38. #include <graphics/gfxbase.h>
  39. #include <devices/printer.h>
  40. #include <devices/prtbase.h>
  41. #include <devices/prtgfx.h>
  42. #include <exec/memory.h>
  43. #include <clib/macros.h>
  44. #include <dos/dostags.h>
  45. #include <dos/rdargs.h>
  46. #include <dos/dos.h>
  47.  
  48. #include <inline/stubs.h>
  49. #include <clib/intuition_protos.h>
  50. #include <clib/graphics_protos.h>
  51. #include <clib/layers_protos.h>
  52. /*
  53. #include <clib/utility_protos.h>
  54. #include <clib/exec_protos.h>
  55. */
  56. #include <inline/iffparse.h>
  57. #include <inline/utility.h>
  58. #include <inline/exec.h>
  59. #include <inline/dos.h>
  60.  
  61. #define ushort foo
  62.  
  63. #include <string.h>
  64. #include <signal.h>
  65.  
  66. #undef ushort
  67.  
  68. #include "gx.h"        /* for gx_bitmap; includes std.h */
  69. #include "gsmatrix.h"    /* needed for gxdevice.h */
  70. #include "gxdevice.h"
  71. #include "gserrors.h"
  72. #include "gsprops.h"
  73.  
  74.     /* Here is how to select a default page size format:
  75.      *
  76.      * Either enter include a line such as
  77.      *
  78.      *   #define AMIGA_PAGE_A4 1
  79.      *
  80.      * Somewhere above in this module, or edit the makefile
  81.      * to feature the option
  82.      *
  83.      *   -dAMIGA_PAGE_A4
  84.      *
  85.      * among the device specific flags. Available default page
  86.      * size formats are:
  87.      *
  88.      *   AMIGA_PAGE_A4         European A4 page size (default)
  89.      *   AMIGA_PAGE_LETTER     US letter page size
  90.      *   AMIGA_PAGE_LEGAL      US legal page size
  91.      *   AMIGA_PAGE_LEDGER     US ledger paper size
  92.      *   AMIGA_PAGE_TABLOID    US tabloid paper size
  93.      */
  94.  
  95.     /* Select the default paper size if none specified. */
  96.  
  97. #if !defined(AMIGA_PAGE_A4) && !defined(AMIGA_PAGE_LETTER) && !defined(AMIGA_PAGE_LEGAL) && !defined(AMIGA_PAGE_LEDGER) && !defined(AMIGA_PAGE_TABLOID)
  98. #define AMIGA_PAGE_A4 1
  99. #endif    /* PAGE SIZE */
  100.  
  101.     /* A4 page size (in inches!) */
  102.  
  103. #ifdef AMIGA_PAGE_A4
  104. #define DEFAULT_WIDTH        8.2
  105. #define DEFAULT_HEIGHT        11.6
  106. #endif    /* AMIGA_PAGE_A4 */
  107.  
  108.     /* US letter page size */
  109.  
  110. #ifdef AMIGA_PAGE_LETTER
  111. #define DEFAULT_WIDTH        8.5
  112. #define DEFAULT_HEIGHT        11.0
  113. #endif    /* AMIGA_PAGE_LETTER */
  114.  
  115.     /* US legal page size */
  116.  
  117. #ifdef AMIGA_PAGE_LEGAL
  118. #define DEFAULT_WIDTH        8.5
  119. #define DEFAULT_HEIGHT        14.0
  120. #endif    /* AMIGA_PAGE_LEGAL */
  121.  
  122.     /* US ledger page size */
  123.  
  124. #ifdef AMIGA_PAGE_LEDGER
  125. #define DEFAULT_WIDTH        16.0
  126. #define DEFAULT_HEIGHT        11.0
  127. #endif    /* AMIGA_PAGE_LEDGER */
  128.  
  129.     /* US tabloid page size */
  130.  
  131. #ifdef AMIGA_PAGE_TABLOID
  132. #define DEFAULT_WIDTH        11.0
  133. #define DEFAULT_HEIGHT        17.0
  134. #endif    /* AMIGA_PAGE_LEDGER */
  135.  
  136.     /* Default output file name. */
  137.  
  138. #define DEFAULT_FILENAME    "gs_page"
  139.  
  140.     /* Turn a byte into a 24 bit colour value. */
  141.  
  142. #define SPREAD(i)    ((ULONG)(i) << 24 | (ULONG)(i) << 16 | (ULONG)(i) << 8 | (i))
  143.  
  144.     /* Scroller gadget IDs. */
  145.  
  146. enum    {    VERTICAL_SCROLLER,    HORIZONTAL_SCROLLER,
  147.         UP_ARROW,        DOWN_ARROW,
  148.         LEFT_ARROW,        RIGHT_ARROW,
  149.  
  150.         GADGET_COUNT };
  151.  
  152.     /* Scroller arrow IDs. */
  153.  
  154. enum    {    UP_IMAGE,        DOWN_IMAGE,
  155.         LEFT_IMAGE,        RIGHT_IMAGE,
  156.  
  157.         IMAGE_COUNT };
  158.  
  159.     /* Codes for the MoveAround() routine. */
  160.  
  161. enum    {    MOVE_MIN,MOVE_FAR_DOWN,MOVE_DOWN,MOVE_UP,MOVE_FAR_UP,MOVE_MAX };
  162.  
  163.     /* Some handy bit masks. */
  164.  
  165. #define SIG_KILL    SIGBREAKF_CTRL_C
  166. #define SIG_HANDSHAKE    SIGF_SINGLE
  167.  
  168.     /* Static dimensions of scroller arrows. */
  169.  
  170. #define ARROW_WIDTH    16
  171. #define ARROW_HEIGHT    11
  172.  
  173.     /* The `Help' key raw code. */
  174.  
  175. #define HELP_CODE    95
  176.  
  177.     /* Minimum window inner area dimension. */
  178.  
  179. #define MINIMUM_WIDTH    64
  180. #define MINIMUM_HEIGHT    32
  181.  
  182.     /* Handy superbitmap window macros. */
  183.  
  184. #define LAYERXOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_X)
  185. #define LAYERYOFFSET(w)    ((w) -> RPort -> Layer -> Scroll_Y)
  186.  
  187.     /* User input to listen to. */
  188.  
  189. #define IDCMP_FLAGS    (IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN | IDCMP_MOUSEMOVE | IDCMP_NEWSIZE | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY)
  190.  
  191.     /* Chunk IDs. */
  192.  
  193. #define ID_ILBM        MAKE_ID('I','L','B','M')
  194. #define ID_BMHD        MAKE_ID('B','M','H','D')
  195. #define ID_CMAP        MAKE_ID('C','M','A','P')
  196. #define ID_CAMG        MAKE_ID('C','A','M','G')
  197. #define ID_ANNO        MAKE_ID('A','N','N','O')
  198. #define ID_DPI        MAKE_ID('D','P','I',' ')
  199. #define ID_BODY        MAKE_ID('B','O','D','Y')
  200.  
  201.     /* Chunk contents definitions. */
  202.  
  203. typedef struct
  204. {
  205.     UWORD        w,h;            /* raster width & height in pixels */
  206.     WORD        x,y;            /* position for this image */
  207.     UBYTE        nPlanes;        /* # source bitplanes */
  208.     UBYTE        masking;        /* masking technique */
  209.     UBYTE        compression;        /* compression algoithm */
  210.     UBYTE        pad1;            /* UNUSED.  For consistency, put 0 here.*/
  211.     UWORD        transparentColor;    /* transparent "color number" */
  212.     UBYTE        xAspect,yAspect;    /* aspect ratio, a rational number x/y */
  213.     WORD        pageWidth,pageHeight;    /* source "page" size in pixels */
  214. } BitMapHeader;
  215.  
  216. typedef struct
  217. {
  218.     UWORD        dpi_x;
  219.     UWORD        dpi_y;
  220. } DPIHeader;
  221.  
  222.     /* Packer modes. */
  223.  
  224. #define DUMP        0
  225. #define RUN        1
  226.  
  227.     /* Minimum data run size, maximum data run size and maximum cache size. */
  228.  
  229. #define MINRUN        3
  230. #define MAXRUN        128
  231. #define MAXDAT        128
  232.  
  233.     /* This module actually implements four different Amiga based
  234.      * devices. As the rendering operations are all the same,
  235.      * one single device definition is sufficient.
  236.      */
  237.  
  238. typedef struct gx_device_amiga
  239. {
  240.     gx_device_common;
  241.  
  242.     struct Screen    *screen;    /* Any screen */
  243.     struct Window    *window;    /* Some window to be opened on the Workbench screen */
  244.  
  245.     LONG         super_width,    /* Superbitmap width */
  246.              super_height;    /* Superbitmap height */
  247.  
  248.     struct BitMap    *super_bitmap;    /* Window superbitmap area */
  249.     struct Gadget    **gadget;    /* Scroller gadgets */
  250.     struct Image    **image;    /* Scroller arrow images */
  251.  
  252.     struct Task    *dispatcher;    /* Slider dispatch task */
  253.     struct Process    *main;        /* Main program */
  254.  
  255.     struct RastPort    *rport;        /* Rendering area */
  256.  
  257.     struct IODRPReq *printer;    /* Printer interface data */
  258.     struct MsgPort    *port;        /* Printer io data */
  259.  
  260.     struct ColorMap    *colormap;    /* A black/white colour map */
  261.     struct BitMap    *bitmap;    /* Rendering bitmap data */
  262.     PLANEPTR     bitplane;    /* Rendering raster */
  263.  
  264.     gx_color_index     last_pen;    /* The last colour set */
  265.  
  266.     float         page_width,    /* The page width */
  267.              page_height;    /* The page height */
  268.     char         file_name[256];/* The output file name */
  269.     int         page_count;    /* The page number counter */
  270.  
  271.     int         cube_size;    /* Colour cube size, 0 for b/w */
  272.     struct RastPort    *temp_rport;    /* Temporary raster port for pixmap imaging. */
  273.     UBYTE        *temp_array;    /* Temporary colour manipulation array. */
  274.     LONG        *pens;
  275. } gx_device_amiga;
  276.  
  277.     /* Function prototypes */
  278.  
  279. VOID            set_mono_device(gx_device_amiga *dev);
  280. VOID            set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens);
  281. VOID            set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize);
  282. VOID            DeleteBitMap(struct BitMap *BitMap,BOOL Private);
  283. struct BitMap *        CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private);
  284. VOID            DeleteTempRPort(struct RastPort *Temp);
  285. struct RastPort *    CreateTempRPort(struct RastPort *Source);
  286. LONG            Euclid(LONG a,LONG b);
  287. BYTE *            PutDump(register BYTE *Destination,register LONG Count);
  288. BYTE *            PutRun(register BYTE *Destination,LONG Count,WORD Char);
  289. LONG            PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize);
  290. BOOL            PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap);
  291. BOOL            PutANNO(struct IFFHandle *Handle);
  292. BOOL            PutCAMG(struct IFFHandle *Handle);
  293. BOOL            PutCMAP(struct IFFHandle *Handle);
  294. BOOL            PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI);
  295. BOOL            PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  296. BOOL            SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI);
  297. float            GetInches(STRPTR Buffer);
  298. VOID            DispatchTask(VOID);
  299. VOID            DeleteScrollers(gx_device *dev);
  300. BOOL            CreateScrollers(gx_device *dev,struct Screen *Screen);
  301. VOID            WindowResize(gx_device *dev);
  302. VOID            WindowUpdate(struct Gadget *Gadget,gx_device *dev);
  303. VOID            MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev);
  304. VOID            DispatchSuperWindow(gx_device *dev);
  305. void            devcleanup(VOID);
  306. gx_color_index        amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  307. int            amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  308. LONG *            AllocatePens(struct ViewPort *VPort,LONG CubeSize);
  309. int            amiga_open_default(gx_device *dev);
  310. int            amiga_open_low(gx_device *dev);
  311. int            amiga_open_high(gx_device *dev);
  312. int            amiga_open_super(gx_device *dev);
  313. int            amiga_open_a2024(gx_device *dev);
  314. int            amiga_open_printer(gx_device *dev);
  315. int            amiga_output_page_printer(gx_device *dev,int num_copies,int flush);
  316. int            amiga_close_printer(gx_device *dev);
  317. int            amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data);
  318. int            amiga_open(gx_device *dev,ULONG Mode);
  319. int            amiga_output_page(gx_device *dev,int num_copies,int flush);
  320. int            amiga_close(gx_device *dev);
  321. int            amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  322. int            amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  323. int            amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  324. int            amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color);
  325. int            amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  326. int            amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  327. int            amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  328. int            amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  329. int            amiga_open_ilbm(gx_device *dev);
  330. int            amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush);
  331. int            amiga_close_ilbm(gx_device *dev);
  332. int            amiga_get_props(gx_device *dev,gs_prop_item *plist);
  333. int            amiga_put_props(gx_device *dev,gs_prop_item *plist,int count);
  334. gx_color_index        amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  335. int            amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  336. gx_color_index        amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue);
  337. int            amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]);
  338. int            amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  339. int            amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one);
  340. int            amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h);
  341. int            amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color);
  342. int            amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color);
  343.  
  344.     /* External reference to graphics.library, required for version checking. */
  345.  
  346. extern struct GfxBase *GfxBase;
  347.  
  348.     /* Number of packed bytes and pack buffer. */
  349.  
  350. LONG    PackedBytes;
  351. BYTE    Buffer[MAXDAT + 1];
  352.  
  353.     /* Resolutions associated with display modes. Note: these values
  354.      * have been determined empirically using an A2024 monitor.
  355.      * In essence, your mileage may vary. This table only gives the
  356.      * horizontal resolution and relies on the graphics display
  357.      * data base to give the corresponding vertical resolution
  358.      * (through aspect/ratio information).
  359.      *
  360.      * Not all screen and printer resolutions will be large enough
  361.      * to hold the contents of a Ghostscript page (whose size appears
  362.      * to be hard-coded into the corresponding file), so you may want
  363.      * to use the "scale" operator to make it fit (I suggest something
  364.      * like "0.7 dup scale" for screen output).
  365.      */
  366.  
  367. STATIC struct { ULONG mode; float dpi; } mode_dpi_table[4] =
  368. {
  369.     A2024_MONITOR_ID,    100.0,    /* 1..1024, requires A2024 or Viking monitor */
  370.     SUPER_KEY,        130.0,    /* 1..1280,  35 nS */
  371.     HIRES_KEY,        70.0,    /* 1.. 640,  70 nS */
  372.     LORES_KEY,        35.0    /* 1.. 320, 140 nS */
  373. };
  374.  
  375.     /* Bit masks. */
  376.  
  377. STATIC UBYTE    shift[8] = { 128, 64, 32, 16,  8,  4,  2,  1 },
  378.         masks[8] = { 127,191,223,239,247,251,253,254 };
  379.  
  380.     /* Device routine jump tables */
  381.  
  382. STATIC gx_device_procs amiga_default_procs =
  383. {
  384.     amiga_open_default,
  385.     gx_default_get_initial_matrix,
  386.     gx_default_sync_output,
  387.     amiga_output_page,
  388.     amiga_close,
  389.     amiga_map_rgb_color,
  390.     amiga_map_color_rgb,
  391.     amiga_fill_rectangle,
  392.     gx_default_tile_rectangle,
  393.     amiga_copy_mono,
  394.     amiga_copy_color,
  395.     amiga_draw_line,
  396.     gx_default_get_bits,
  397.     amiga_get_props,
  398.     amiga_put_props
  399. };
  400.  
  401. STATIC gx_device_procs amiga_low_procs =
  402. {
  403.     amiga_open_low,
  404.     gx_default_get_initial_matrix,
  405.     gx_default_sync_output,
  406.     amiga_output_page,
  407.     amiga_close,
  408.     amiga_map_rgb_color,
  409.     amiga_map_color_rgb,
  410.     amiga_fill_rectangle,
  411.     gx_default_tile_rectangle,
  412.     amiga_copy_mono,
  413.     amiga_copy_color,
  414.     amiga_draw_line,
  415.     gx_default_get_bits,
  416.     amiga_get_props,
  417.     amiga_put_props
  418. };
  419.  
  420. STATIC gx_device_procs amiga_high_procs =
  421. {
  422.     amiga_open_high,
  423.     gx_default_get_initial_matrix,
  424.     gx_default_sync_output,
  425.     amiga_output_page,
  426.     amiga_close,
  427.     amiga_map_rgb_color,
  428.     amiga_map_color_rgb,
  429.     amiga_fill_rectangle,
  430.     gx_default_tile_rectangle,
  431.     amiga_copy_mono,
  432.     amiga_copy_color,
  433.     amiga_draw_line,
  434.     gx_default_get_bits,
  435.     amiga_get_props,
  436.     amiga_put_props
  437. };
  438.  
  439. STATIC gx_device_procs amiga_super_procs =
  440. {
  441.     amiga_open_super,
  442.     gx_default_get_initial_matrix,
  443.     gx_default_sync_output,
  444.     amiga_output_page,
  445.     amiga_close,
  446.     amiga_map_rgb_color,
  447.     amiga_map_color_rgb,
  448.     amiga_fill_rectangle,
  449.     gx_default_tile_rectangle,
  450.     amiga_copy_mono,
  451.     amiga_copy_color,
  452.     amiga_draw_line,
  453.     gx_default_get_bits,
  454.     amiga_get_props,
  455.     amiga_put_props
  456. };
  457.  
  458. STATIC gx_device_procs amiga_a2024_procs =
  459. {
  460.     amiga_open_a2024,
  461.     gx_default_get_initial_matrix,
  462.     gx_default_sync_output,
  463.     amiga_output_page,
  464.     amiga_close,
  465.     amiga_map_rgb_color,
  466.     amiga_map_color_rgb,
  467.     amiga_fill_rectangle,
  468.     gx_default_tile_rectangle,
  469.     amiga_copy_mono,
  470.     amiga_copy_color,
  471.     amiga_draw_line,
  472.     gx_default_get_bits,
  473.     amiga_get_props,
  474.     amiga_put_props
  475. };
  476.  
  477. STATIC gx_device_procs amiga_printer_procs =
  478. {
  479.     amiga_open_printer,
  480.     gx_default_get_initial_matrix,
  481.     gx_default_sync_output,
  482.     amiga_output_page_printer,
  483.     amiga_close_printer,
  484.     amiga_map_rgb_color,
  485.     amiga_map_color_rgb,
  486.     amiga_fill_rectangle_raw,
  487.     gx_default_tile_rectangle,
  488.     amiga_copy_mono_raw,
  489.     amiga_copy_color_raw,
  490.     amiga_draw_line_raw,
  491.     amiga_get_bits,
  492.     amiga_get_props,
  493.     amiga_put_props
  494. };
  495.  
  496. STATIC gx_device_procs amiga_ilbm_procs =
  497. {
  498.     amiga_open_ilbm,
  499.     gx_default_get_initial_matrix,
  500.     gx_default_sync_output,
  501.     amiga_output_page_ilbm,
  502.     amiga_close_ilbm,
  503.     amiga_map_rgb_color,
  504.     amiga_map_color_rgb,
  505.     amiga_fill_rectangle_raw,
  506.     gx_default_tile_rectangle,
  507.     amiga_copy_mono_raw,
  508.     amiga_copy_color_raw,
  509.     amiga_draw_line_raw,
  510.     amiga_get_bits,
  511.     amiga_get_props,
  512.     amiga_put_props
  513. };
  514.  
  515.     /* Default device: opens a window on the Workbench screen and renders into it */
  516.  
  517. gx_device_amiga gs_amiga_device =
  518. {
  519.     sizeof(gx_device_amiga),    /* params_size */
  520.     &amiga_default_procs,        /* procs */
  521.     "amiga",            /* dname */
  522.     0, 0,                /* width, height */
  523.     72.27, 72.27,            /* xdpi, ydpi */
  524.     no_margins,            /* margins */
  525.     dci_black_and_white,        /* color info */
  526.     0,                /* is_open */
  527.  
  528.     NULL,                /* screen */
  529.     NULL,                /* window */
  530.  
  531.     0,                /* super_width */
  532.     0,                /* super_height */
  533.     NULL,                /* super_bitmap */
  534.     NULL,                /* gadget */
  535.     NULL,                /* image */
  536.  
  537.     NULL,                /* dispatcher */
  538.     NULL,                /* main */
  539.  
  540.     NULL,                /* rport */
  541.  
  542.     NULL,                /* printer */
  543.     NULL,                /* port */
  544.     NULL,                /* colormap */
  545.     NULL,                /* bitmap */
  546.     NULL,                /* bitplane */
  547.  
  548.     1,                /* last_pen */
  549.  
  550.     DEFAULT_WIDTH,            /* page width */
  551.     DEFAULT_HEIGHT,            /* page height */
  552.     DEFAULT_FILENAME,        /* output file */
  553.     1,                /* page counter */
  554.  
  555.     0,                /* cube_size */
  556.     NULL,                /* temp_rport */
  557.     NULL,                /* temp_array */
  558.     NULL                /* pens */
  559. };
  560.  
  561.     /* Low resolution device: opens a lores custom screen and renders into it */
  562.  
  563. gx_device_amiga gs_amiga_low_device =
  564. {
  565.     sizeof(gx_device_amiga),    /* params_size */
  566.     &amiga_low_procs,        /* procs */
  567.     "amiga_low",            /* dname */
  568.     0, 0,                /* width, height */
  569.     72.27, 72.27,            /* xdpi, ydpi */
  570.     no_margins,            /* margins */
  571.     dci_black_and_white,        /* color info */
  572.     0,                /* is_open */
  573.  
  574.     NULL,                /* screen */
  575.     NULL,                /* window */
  576.  
  577.     0,                /* super_width */
  578.     0,                /* super_height */
  579.     NULL,                /* super_bitmap */
  580.     NULL,                /* gadget */
  581.     NULL,                /* image */
  582.  
  583.     NULL,                /* dispatcher */
  584.     NULL,                /* main */
  585.  
  586.     NULL,                /* rport */
  587.  
  588.     NULL,                /* printer */
  589.     NULL,                /* port */
  590.     NULL,                /* colormap */
  591.     NULL,                /* bitmap */
  592.     NULL,                /* bitplane */
  593.  
  594.     1,                /* last_pen */
  595.  
  596.     DEFAULT_WIDTH,            /* page width */
  597.     DEFAULT_HEIGHT,            /* page height */
  598.     DEFAULT_FILENAME,        /* output file */
  599.     1,                /* page counter */
  600.  
  601.     0,                /* cube_size */
  602.     NULL,                /* temp_rport */
  603.     NULL,                /* temp_array */
  604.     NULL                /* pens */
  605. };
  606.  
  607.     /* High resolution device: opens a highres-interlaced custom screen */
  608.  
  609. gx_device_amiga gs_amiga_high_device =
  610. {
  611.     sizeof(gx_device_amiga),    /* params_size */
  612.     &amiga_high_procs,        /* procs */
  613.     "amiga_high",            /* dname */
  614.     0, 0,                /* width, height */
  615.     72.27, 72.27,            /* xdpi, ydpi */
  616.     no_margins,            /* margins */
  617.     dci_black_and_white,        /* color info */
  618.     0,                /* is_open */
  619.  
  620.     NULL,                /* screen */
  621.     NULL,                /* window */
  622.  
  623.     0,                /* super_width */
  624.     0,                /* super_height */
  625.     NULL,                /* super_bitmap */
  626.     NULL,                /* gadget */
  627.     NULL,                /* image */
  628.  
  629.     NULL,                /* dispatcher */
  630.     NULL,                /* main */
  631.  
  632.     NULL,                /* rport */
  633.  
  634.     NULL,                /* printer */
  635.     NULL,                /* port */
  636.     NULL,                /* colormap */
  637.     NULL,                /* bitmap */
  638.     NULL,                /* bitplane */
  639.  
  640.     1,                /* last_pen */
  641.  
  642.     DEFAULT_WIDTH,            /* page width */
  643.     DEFAULT_HEIGHT,            /* page height */
  644.     DEFAULT_FILENAME,        /* output file */
  645.     1,                /* page counter */
  646.  
  647.     0,                /* cube_size */
  648.     NULL,                /* temp_rport */
  649.     NULL,                /* temp_array */
  650.     NULL                /* pens */
  651. };
  652.  
  653.     /* Super high resolution device: opens a super-highres-interlaced custom screen */
  654.  
  655. gx_device_amiga gs_amiga_super_device =
  656. {
  657.     sizeof(gx_device_amiga),    /* params_size */
  658.     &amiga_super_procs,        /* procs */
  659.     "amiga_super",            /* dname */
  660.     0, 0,                /* width, height */
  661.     72.27, 72.27,            /* xdpi, ydpi */
  662.     no_margins,            /* margins */
  663.     dci_black_and_white,        /* color info */
  664.     0,                /* is_open */
  665.  
  666.     NULL,                /* screen */
  667.     NULL,                /* window */
  668.  
  669.     0,                /* super_width */
  670.     0,                /* super_height */
  671.     NULL,                /* super_bitmap */
  672.     NULL,                /* gadget */
  673.     NULL,                /* image */
  674.  
  675.     NULL,                /* dispatcher */
  676.     NULL,                /* main */
  677.  
  678.     NULL,                /* rport */
  679.  
  680.     NULL,                /* printer */
  681.     NULL,                /* port */
  682.     NULL,                /* colormap */
  683.     NULL,                /* bitmap */
  684.     NULL,                /* bitplane */
  685.  
  686.     1,                /* last_pen */
  687.  
  688.     DEFAULT_WIDTH,            /* page width */
  689.     DEFAULT_HEIGHT,            /* page height */
  690.     DEFAULT_FILENAME,        /* output file */
  691.     1,                /* page counter */
  692.  
  693.     0,                /* cube_size */
  694.     NULL,                /* temp_rport */
  695.     NULL,                /* temp_array */
  696.     NULL                /* pens */
  697. };
  698.  
  699.     /* A2024 device: opens an A2024 custom screen */
  700.  
  701. gx_device_amiga gs_amiga_a2024_device =
  702. {
  703.     sizeof(gx_device_amiga),    /* params_size */
  704.     &amiga_a2024_procs,        /* procs */
  705.     "amiga_a2024",            /* dname */
  706.     0, 0,                /* width, height */
  707.     72.27, 72.27,            /* xdpi, ydpi */
  708.     no_margins,            /* margins */
  709.     dci_black_and_white,        /* color info */
  710.     0,                /* is_open */
  711.  
  712.     NULL,                /* screen */
  713.     NULL,                /* window */
  714.  
  715.     0,                /* super_width */
  716.     0,                /* super_height */
  717.     NULL,                /* super_bitmap */
  718.     NULL,                /* gadget */
  719.     NULL,                /* image */
  720.  
  721.     NULL,                /* dispatcher */
  722.     NULL,                /* main */
  723.  
  724.     NULL,                /* rport */
  725.  
  726.     NULL,                /* printer */
  727.     NULL,                /* port */
  728.     NULL,                /* colormap */
  729.     NULL,                /* bitmap */
  730.     NULL,                /* bitplane */
  731.  
  732.     1,                /* last_pen */
  733.  
  734.     DEFAULT_WIDTH,            /* page width */
  735.     DEFAULT_HEIGHT,            /* page height */
  736.     DEFAULT_FILENAME,        /* output file */
  737.     1,                /* page counter */
  738.  
  739.     0,                /* cube_size */
  740.     NULL,                /* temp_rport */
  741.     NULL,                /* temp_array */
  742.     NULL                /* pens */
  743. };
  744.  
  745.     /* Printer device: renders the imagery and sends it to the printer */
  746.  
  747. gx_device_amiga gs_amiga_printer_device =
  748. {
  749.     sizeof(gx_device_amiga),    /* params_size */
  750.     &amiga_printer_procs,        /* procs */
  751.     "amiga_printer",        /* dname */
  752.     0, 0,                /* width, height */
  753.     72.27, 72.27,            /* xdpi, ydpi */
  754.     no_margins,            /* margins */
  755.     dci_black_and_white,        /* color info */
  756.     0,                /* is_open */
  757.  
  758.     NULL,                /* screen */
  759.     NULL,                /* window */
  760.  
  761.     0,                /* super_width */
  762.     0,                /* super_height */
  763.     NULL,                /* super_bitmap */
  764.     NULL,                /* gadget */
  765.     NULL,                /* image */
  766.  
  767.     NULL,                /* dispatcher */
  768.     NULL,                /* main */
  769.  
  770.     NULL,                /* rport */
  771.  
  772.     NULL,                /* printer */
  773.     NULL,                /* port */
  774.     NULL,                /* colormap */
  775.     NULL,                /* bitmap */
  776.     NULL,                /* bitplane */
  777.  
  778.     1,                /* last_pen */
  779.  
  780.     DEFAULT_WIDTH,            /* page width */
  781.     DEFAULT_HEIGHT,            /* page height */
  782.     DEFAULT_FILENAME,        /* output file */
  783.     1,                /* page counter */
  784.  
  785.     0,                /* cube_size */
  786.     NULL,                /* temp_rport */
  787.     NULL,                /* temp_array */
  788.     NULL                /* pens */
  789. };
  790.  
  791.     /* ILBM device: renders the imagery and saves it to an IFF-ILBM file. */
  792.  
  793. gx_device_amiga gs_amiga_ilbm_device =
  794. {
  795.     sizeof(gx_device_amiga),    /* params_size */
  796.     &amiga_ilbm_procs,        /* procs */
  797.     "amiga_ilbm",            /* dname */
  798.     0, 0,                /* width, height */
  799.     72.27, 72.27,            /* xdpi, ydpi */
  800.     no_margins,            /* margins */
  801.     dci_black_and_white,        /* color info */
  802.     0,                /* is_open */
  803.  
  804.     NULL,                /* screen */
  805.     NULL,                /* window */
  806.  
  807.     0,                /* super_width */
  808.     0,                /* super_height */
  809.     NULL,                /* super_bitmap */
  810.     NULL,                /* gadget */
  811.     NULL,                /* image */
  812.  
  813.     NULL,                /* dispatcher */
  814.     NULL,                /* main */
  815.  
  816.     NULL,                /* rport */
  817.  
  818.     NULL,                /* printer */
  819.     NULL,                /* port */
  820.     NULL,                /* colormap */
  821.     NULL,                /* bitmap */
  822.     NULL,                /* bitplane */
  823.  
  824.     1,                /* last_pen */
  825.  
  826.     DEFAULT_WIDTH,            /* page width */
  827.     DEFAULT_HEIGHT,            /* page height */
  828.     DEFAULT_FILENAME,        /* output file */
  829.     1,                /* page counter */
  830.  
  831.     0,                /* cube_size */
  832.     NULL,                /* temp_rport */
  833.     NULL,                /* temp_array */
  834.     NULL                /* pens */
  835. };
  836.  
  837.     /* Dark (black) and light (white) rendering colours; the default device
  838.      * determines the actual colours to be used by looking into the screen
  839.      * colour lookup table, the other device drivers leave these values
  840.      * untouched.
  841.      */
  842.  
  843. STATIC UBYTE    DarkPen        = 0,
  844.         LightPen    = 1;
  845.  
  846.     /* Cheap, but effective ;-) */
  847.  
  848. #define xdev ((gx_device_amiga *)dev)
  849.  
  850.     /* set_mono_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  851.      *
  852.      *    Reconfigure a device for monochrome output.
  853.      */
  854.  
  855. VOID
  856. set_mono_device(gx_device_amiga *dev)
  857. {
  858.     xdev -> color_info . depth        = 1;
  859.     xdev -> color_info . num_components    = 1;
  860.     xdev -> color_info . max_gray        = 1;
  861.     xdev -> color_info . max_rgb        = 0;
  862.     xdev -> color_info . dither_gray    = 2;
  863.     xdev -> color_info . dither_rgb        = 0;
  864.  
  865.     xdev -> procs -> copy_color        = amiga_copy_color;
  866.     xdev -> procs -> map_rgb_color        = amiga_map_rgb_color;
  867.     xdev -> procs -> map_color_rgb        = amiga_map_color_rgb;
  868.  
  869.     xdev -> cube_size            = 0;
  870. }
  871.  
  872.     /* set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens):
  873.      *
  874.      *    Reconfigure a device for colour output.
  875.      */
  876.  
  877. VOID
  878. set_colour_device(gx_device_amiga *dev,int cube_size,LONG *pens)
  879. {
  880.     xdev -> color_info . depth        = 8;
  881.     xdev -> color_info . num_components    = 3;
  882.     xdev -> color_info . max_gray        = cube_size - 1;
  883.     xdev -> color_info . max_rgb        = cube_size - 1;
  884.     xdev -> color_info . dither_gray    = cube_size;
  885.     xdev -> color_info . dither_rgb        = cube_size;
  886.  
  887.     xdev -> procs -> copy_color        = amiga_copy_color8;
  888.  
  889.         /* Any colours to be remapped? */
  890.  
  891.     if(pens)
  892.     {
  893.         xdev -> procs -> map_rgb_color    = amiga_color_map_rgb_color_pen;
  894.         xdev -> procs -> map_color_rgb    = amiga_color_map_color_rgb_pen;
  895.         xdev -> pens            = pens;
  896.     }
  897.     else
  898.     {
  899.         xdev -> procs -> map_rgb_color    = amiga_color_map_rgb_color;
  900.         xdev -> procs -> map_color_rgb    = amiga_color_map_color_rgb;
  901.     }
  902.  
  903.         /* Remember the size of the RGB cube. */
  904.  
  905.     xdev -> cube_size            = cube_size;
  906. }
  907.  
  908.     /* set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize):
  909.      *
  910.      *    Configure the printer device for colour output.
  911.      */
  912.  
  913. VOID
  914. set_colour_printer_device(gx_device_amiga *dev,LONG CubeSize)
  915. {
  916.     xdev -> color_info . depth        = 16;
  917.     xdev -> color_info . num_components    = 3;
  918.     xdev -> color_info . max_gray        = CubeSize - 1;
  919.     xdev -> color_info . max_rgb        = CubeSize - 1;
  920.     xdev -> color_info . dither_gray    = CubeSize;
  921.     xdev -> color_info . dither_rgb        = CubeSize;
  922.  
  923.     xdev -> procs -> fill_rectangle        = amiga_fill_rectangle_raw_color;
  924.     xdev -> procs -> copy_mono        = amiga_copy_mono_raw_color;
  925.     xdev -> procs -> copy_color        = amiga_copy_color_raw_color16;
  926.     xdev -> procs -> draw_line        = amiga_draw_line_raw_color;
  927.     xdev -> procs -> get_bits        = gx_default_get_bits;
  928.     xdev -> procs -> map_rgb_color        = amiga_color_map_rgb_color;
  929.     xdev -> procs -> map_color_rgb        = amiga_color_map_color_rgb;
  930.     xdev -> cube_size            = CubeSize;
  931. }
  932.  
  933.     /* DeleteBitMap(struct BitMap *BitMap,BOOL Private):
  934.      *
  935.      *    Free memory associated with a custom rendering bitmap.
  936.      */
  937.  
  938. VOID
  939. DeleteBitMap(struct BitMap *BitMap,BOOL Private)
  940. {
  941.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  942.         FreeBitMap(BitMap);
  943.     else
  944.     {
  945.         LONG i;
  946.  
  947.         for(i = 0 ; i < BitMap -> Depth ; i++)
  948.         {
  949.             if(BitMap -> Planes[i])
  950.                 FreeVec(BitMap -> Planes[i]);
  951.         }
  952.  
  953.         FreeVec(BitMap);
  954.     }
  955. }
  956.  
  957.     /* CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private):
  958.      *
  959.      *    Create a custom rendering bitmap.
  960.      */
  961.  
  962. struct BitMap *
  963. CreateBitMap(LONG Width,LONG Height,LONG Depth,ULONG Flags,struct BitMap *Friend,BOOL Private)
  964. {
  965.     if(GfxBase -> LibNode . lib_Version >= 39 && !Private)
  966.         return(AllocBitMap(Width,Height,Depth,Flags,Friend));
  967.     else
  968.     {
  969.         struct BitMap    *BitMap;
  970.         LONG         Plus;
  971.         ULONG         MemType;
  972.  
  973.             /* Bitmap structure needs to be padded if more
  974.              * than the standard eight bitplanes are to be
  975.              * allocated.
  976.              */
  977.  
  978.         if(Depth > 8)
  979.             Plus = (Depth - 8) * sizeof(PLANEPTR);
  980.         else
  981.             Plus = 0;
  982.  
  983.         if(Private)
  984.             MemType = MEMF_ANY;
  985.         else
  986.             MemType = MEMF_CHIP;
  987.  
  988.         if(BitMap = (struct BitMap *)AllocVec(sizeof(struct BitMap) + Plus,MEMF_ANY | MEMF_CLEAR))
  989.         {
  990.             LONG i,PageSize;
  991.  
  992.             InitBitMap(BitMap,Depth,Width,Height);
  993.  
  994.             PageSize = BitMap -> BytesPerRow * BitMap -> Rows;
  995.  
  996.             for(i = 0 ; i < BitMap -> Depth ; i++)
  997.             {
  998.                 if(!(BitMap -> Planes[i] = (PLANEPTR)AllocVec(PageSize,MemType)))
  999.                 {
  1000.                     LONG j;
  1001.  
  1002.                     for(j = 0 ; j < i ; j++)
  1003.                         FreeVec(BitMap -> Planes[j]);
  1004.  
  1005.                     FreeVec(BitMap);
  1006.  
  1007.                     return(NULL);
  1008.                 }
  1009.             }
  1010.  
  1011.             return(BitMap);
  1012.         }
  1013.     }
  1014. }
  1015.  
  1016.     /* DeleteTempRPort(struct RastPort *Temp):
  1017.      *
  1018.      *    Free memory associated with a temporary raster port.
  1019.      */
  1020.  
  1021. VOID
  1022. DeleteTempRPort(struct RastPort *Temp)
  1023. {
  1024.     DeleteBitMap(Temp -> BitMap,FALSE);
  1025.  
  1026.     FreeVec(Temp);
  1027. }
  1028.  
  1029.     /* CreateTempRPort(struct RastPort *Source):
  1030.      *
  1031.      *    Allocate memory for temporary raster port (one line high).
  1032.      */
  1033.  
  1034. struct RastPort *
  1035. CreateTempRPort(struct RastPort *Source)
  1036. {
  1037.     struct RastPort *Temp;
  1038.  
  1039.     if(Temp = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  1040.     {
  1041.         LONG Width,Depth;
  1042.  
  1043.         CopyMem(Source,Temp,sizeof(struct RastPort));
  1044.  
  1045.         Temp -> Layer = NULL;
  1046.  
  1047.         if(GfxBase -> LibNode . lib_Version >= 39)
  1048.         {
  1049.             Width    = GetBitMapAttr(Source -> BitMap,BMA_WIDTH);
  1050.             Depth    = GetBitMapAttr(Source -> BitMap,BMA_DEPTH);
  1051.         }
  1052.         else
  1053.         {
  1054.             Width    = Source -> BitMap -> BytesPerRow * 8;
  1055.             Depth    = Source -> BitMap -> Depth;
  1056.         }
  1057.  
  1058.         if(Temp -> BitMap = CreateBitMap(Width,1,Depth,NULL,Source -> BitMap,FALSE))
  1059.             return(Temp);
  1060.         else
  1061.             FreeVec(Temp);
  1062.     }
  1063.  
  1064.     return(NULL);
  1065. }
  1066.  
  1067.     /* Euclid(LONG a,LONG b):
  1068.      *
  1069.      *    Compute the greatest common divisor of two integers.
  1070.      */
  1071.  
  1072. LONG
  1073. Euclid(LONG a,LONG b)
  1074. {
  1075.     do
  1076.     {
  1077.         if(a < b)
  1078.         {
  1079.             LONG t;
  1080.  
  1081.             t = a;
  1082.             a = b;
  1083.             b = t;
  1084.         }
  1085.  
  1086.         a = a % b;
  1087.     }
  1088.     while(a);
  1089.  
  1090.     return(b);
  1091. }
  1092.  
  1093.     /* PutDump(register BYTE *Destination,register LONG Count):
  1094.      *
  1095.      *    Store a byte dump.
  1096.      */
  1097.  
  1098. BYTE *
  1099. PutDump(register BYTE *Destination,register LONG Count)
  1100. {
  1101.     register BYTE *Source = Buffer;
  1102.  
  1103.     *Destination++     = Count - 1;
  1104.      PackedBytes    += Count + 1;
  1105.  
  1106.     while(Count--)
  1107.         *Destination++ = *Source++;
  1108.  
  1109.     return(Destination);
  1110. }
  1111.  
  1112.     /* PutRun(register BYTE *Destination,LONG Count,WORD Char):
  1113.      *
  1114.      *    Store a byte run.
  1115.      */
  1116.  
  1117. BYTE *
  1118. PutRun(register BYTE *Destination,LONG Count,WORD Char)
  1119. {
  1120.     *Destination++     = -(Count - 1);
  1121.     *Destination++     = Char;
  1122.      PackedBytes    += 2; 
  1123.  
  1124.     return(Destination);
  1125. }
  1126.  
  1127.     /* PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize):
  1128.      *
  1129.      *    Pack a raster line using the CmpByteRun1 algorithm.
  1130.      */
  1131.  
  1132. LONG
  1133. PackRow(PLANEPTR *SourcePtr,register BYTE *Destination,LONG RowSize)
  1134. {
  1135.     register BYTE *Source = *SourcePtr;
  1136.  
  1137.     WORD    Buffered    = 1,
  1138.         RunStart    = 0;
  1139.     BYTE    Mode        = DUMP,
  1140.         LastChar,
  1141.         Char;
  1142.  
  1143.     PackedBytes = 0;
  1144.  
  1145.     Buffer[0] = LastChar = Char = *Source++;
  1146.  
  1147.     RowSize--;
  1148.  
  1149.     while(RowSize--)
  1150.     {
  1151.         Buffer[Buffered++] = Char = *Source++;
  1152.  
  1153.         if(Mode)
  1154.         {
  1155.             if((Char != LastChar) || (Buffered - RunStart > MAXRUN))
  1156.             {
  1157.                 Destination    = PutRun(Destination,Buffered - 1 - RunStart,LastChar);
  1158.                 Buffer[0]    = Char;
  1159.                 Buffered    = 1;
  1160.                 RunStart    = 0;
  1161.                 Mode        = DUMP;
  1162.             }
  1163.         }
  1164.         else
  1165.         {
  1166.             if(Buffered > MAXDAT)
  1167.             {
  1168.                 Destination    = PutDump(Destination,Buffered - 1);
  1169.                 Buffer[0]    = Char;
  1170.                 Buffered    = 1;
  1171.                 RunStart    = 0;
  1172.             }
  1173.             else
  1174.             {
  1175.                 if(Char == LastChar)
  1176.                 {
  1177.                     if(Buffered - RunStart >= MINRUN)
  1178.                     {
  1179.                         if(RunStart)
  1180.                             Destination = PutDump(Destination,RunStart);
  1181.  
  1182.                         Mode = RUN;
  1183.                     }
  1184.                     else
  1185.                     {
  1186.                         if(!RunStart)
  1187.                             Mode = RUN;
  1188.                     }
  1189.                 }
  1190.                 else
  1191.                     RunStart = Buffered - 1;
  1192.             }
  1193.         }
  1194.  
  1195.         LastChar = Char;
  1196.     }
  1197.  
  1198.     if(Mode)
  1199.         PutRun(Destination,Buffered - RunStart,LastChar);
  1200.     else
  1201.         PutDump(Destination,Buffered);
  1202.  
  1203.     *SourcePtr = Source;
  1204.  
  1205.     return(PackedBytes);
  1206. }
  1207.  
  1208.     /* PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap):
  1209.      *
  1210.      *    Store a bitmap in a BODY chunk.
  1211.      */
  1212.  
  1213. BOOL
  1214. PutBODY(struct IFFHandle *Handle,struct BitMap *BitMap)
  1215. {
  1216.     PLANEPTR    *Planes;
  1217.     BYTE        *PackBuffer;
  1218.     BOOL         Success = FALSE;
  1219.     LONG         PackedBytes,
  1220.              i,j;
  1221.  
  1222.         /* Allocate the bitplane information. */
  1223.  
  1224.     if(Planes = (PLANEPTR *)AllocVec(BitMap -> Depth * sizeof(PLANEPTR *),MEMF_ANY | MEMF_CLEAR))
  1225.     {
  1226.             /* Allocate the compression buffer. */
  1227.  
  1228.         if(PackBuffer = (BYTE *)AllocVec(BitMap -> BytesPerRow * 2,MEMF_ANY))
  1229.         {
  1230.                 /* Copy the planes over. */
  1231.  
  1232.             for(i = 0 ; i < BitMap -> Depth ; i++)
  1233.                 Planes[i] = BitMap -> Planes[i];
  1234.  
  1235.             if(!PushChunk(Handle,0,ID_BODY,IFFSIZE_UNKNOWN))
  1236.             {
  1237.                 Success = TRUE;
  1238.  
  1239.                     /* Run down the rows. */
  1240.  
  1241.                 for(i = 0 ; Success && i < BitMap -> Rows ; i++)
  1242.                 {
  1243.                     for(j = 0 ; Success && j < BitMap -> Depth ; j++)
  1244.                     {
  1245.                             /* Pack the data. */
  1246.  
  1247.                         PackedBytes = PackRow(&Planes[j],PackBuffer,BitMap -> BytesPerRow);
  1248.  
  1249.                             /* Write it to disk. */
  1250.  
  1251.                         if(WriteChunkRecords(Handle,PackBuffer,PackedBytes,1) != 1)
  1252.                             Success = FALSE;
  1253.                     }
  1254.                 }
  1255.  
  1256.                 if(PopChunk(Handle))
  1257.                     Success = FALSE;
  1258.             }
  1259.  
  1260.             FreeVec(PackBuffer);
  1261.         }
  1262.  
  1263.         FreeVec(Planes);
  1264.     }
  1265.  
  1266.     return(Success);
  1267. }
  1268.  
  1269.     /* PutANNO(struct IFFHandle *Handle):
  1270.      *
  1271.      *    Store annotation chunk.
  1272.      */
  1273.  
  1274. BOOL
  1275. PutANNO(struct IFFHandle *Handle)
  1276. {
  1277.     STATIC STRPTR Note = "Rendered by GNU Ghostscript 2.6.0";
  1278.  
  1279.     if(!PushChunk(Handle,0,ID_ANNO,strlen(Note)))
  1280.     {
  1281.         if(WriteChunkRecords(Handle,Note,strlen(Note),1) == 1)
  1282.         {
  1283.             if(!PopChunk(Handle))
  1284.                 return(TRUE);
  1285.         }
  1286.     }
  1287.  
  1288.     return(FALSE);
  1289. }
  1290.  
  1291.     /* PutCAMG(struct IFFHandle *Handle):
  1292.      *
  1293.      *    Store display mode chunk.
  1294.      */
  1295.  
  1296. BOOL
  1297. PutCAMG(struct IFFHandle *Handle)
  1298. {
  1299.     ULONG ViewModes = HIRESLACE_KEY;
  1300.  
  1301.     if(!PushChunk(Handle,0,ID_CAMG,sizeof(ULONG)))
  1302.     {
  1303.         if(WriteChunkRecords(Handle,&ViewModes,sizeof(ULONG),1) == 1)
  1304.         {
  1305.             if(!PopChunk(Handle))
  1306.                 return(TRUE);
  1307.         }
  1308.     }
  1309.  
  1310.     return(FALSE);
  1311. }
  1312.  
  1313.     /* PutCMAP(struct IFFHandle *Handle):
  1314.      *
  1315.      *    Store colour map chunk.
  1316.      */
  1317.  
  1318. BOOL
  1319. PutCMAP(struct IFFHandle *Handle)
  1320. {
  1321.     STATIC UBYTE Colours[2][3] =
  1322.     {
  1323.         0x00,0x00,0x00,
  1324.         0xFF,0xFF,0xFF
  1325.     };
  1326.  
  1327.     if(!PushChunk(Handle,0,ID_CMAP,sizeof(Colours)))
  1328.     {
  1329.         if(WriteChunkRecords(Handle,Colours,2,3) == 3)
  1330.         {
  1331.             if(!PopChunk(Handle))
  1332.                 return(TRUE);
  1333.         }
  1334.     }
  1335.  
  1336.     return(FALSE);
  1337. }
  1338.  
  1339.     /* PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI):
  1340.      *
  1341.      *    Store DPI chunk.
  1342.      */
  1343.  
  1344. BOOL
  1345. PutDPI(struct IFFHandle *Handle,UWORD X_DPI,UWORD Y_DPI)
  1346. {
  1347.     DPIHeader Header;
  1348.  
  1349.     Header . dpi_x = X_DPI;
  1350.     Header . dpi_y = Y_DPI;
  1351.  
  1352.     if(!PushChunk(Handle,0,ID_DPI,sizeof(Header)))
  1353.     {
  1354.         if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1355.         {
  1356.             if(!PopChunk(Handle))
  1357.                 return(TRUE);
  1358.         }
  1359.     }
  1360.  
  1361.     return(FALSE);
  1362. }
  1363.  
  1364.     /* PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1365.      *
  1366.      *    Store BMHD chunk.
  1367.      */
  1368.  
  1369. BOOL
  1370. PutBMHD(struct IFFHandle *Handle,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1371. {
  1372.         /* Valid parameters? */
  1373.  
  1374.     if(X_DPI > 0 && Y_DPI > 0 && Width > 0 && Height > 0)
  1375.     {
  1376.         BitMapHeader    Header;
  1377.         UWORD        gcd;
  1378.  
  1379.             /* So we can store neat & small
  1380.              * aspect ration values.
  1381.              */
  1382.  
  1383.         gcd = Euclid(X_DPI,Y_DPI);
  1384.  
  1385.         Header . w            = Width;
  1386.         Header . h            = Height;
  1387.         Header . pageWidth        = Width;
  1388.         Header . pageHeight        = Height;
  1389.         Header . x            = 0;
  1390.         Header . y            = 0;
  1391.         Header . nPlanes        = 1;
  1392.         Header . masking        = 0;
  1393.         Header . compression        = 1;
  1394.         Header . pad1            = 0;
  1395.         Header . transparentColor    = 0;
  1396.         Header . xAspect        = X_DPI / gcd;
  1397.         Header . yAspect        = Y_DPI / gcd;
  1398.  
  1399.         if(!PushChunk(Handle,0,ID_BMHD,sizeof(Header)))
  1400.         {
  1401.             if(WriteChunkRecords(Handle,&Header,sizeof(Header),1) == 1)
  1402.             {
  1403.                 if(!PopChunk(Handle))
  1404.                     return(TRUE);
  1405.             }
  1406.         }
  1407.     }
  1408.  
  1409.     return(FALSE);
  1410. }
  1411.  
  1412.     /* SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI):
  1413.      *
  1414.      *    Store a bitmap in an IFF-ILBM file.
  1415.      */
  1416.  
  1417. BOOL
  1418. SaveBitMap(STRPTR Name,struct BitMap *BitMap,LONG Width,LONG Height,UWORD X_DPI,UWORD Y_DPI)
  1419. {
  1420.     struct IFFHandle    *Handle;
  1421.     BOOL             Success = FALSE;
  1422.  
  1423.     if(Handle = AllocIFF())
  1424.     {
  1425.         if(Handle -> iff_Stream = Open(Name,MODE_NEWFILE))
  1426.         {
  1427.             InitIFFasDOS(Handle);
  1428.  
  1429.             if(!OpenIFF(Handle,IFFF_WRITE))
  1430.             {
  1431.                 if(!PushChunk(Handle,ID_ILBM,ID_FORM,IFFSIZE_UNKNOWN))
  1432.                 {
  1433.                     if(PutBMHD(Handle,Width,Height,X_DPI,Y_DPI))
  1434.                     {
  1435.                         if(PutANNO(Handle))
  1436.                         {
  1437.                             if(PutCMAP(Handle))
  1438.                             {
  1439.                                 if(PutCAMG(Handle))
  1440.                                 {
  1441.                                     if(PutDPI(Handle,X_DPI,Y_DPI))
  1442.                                     {
  1443.                                         if(PutBODY(Handle,BitMap))
  1444.                                             Success = TRUE;
  1445.                                     }
  1446.                                 }
  1447.                             }
  1448.                         }
  1449.                     }
  1450.  
  1451.                     if(PopChunk(Handle))
  1452.                         Success = FALSE;
  1453.                 }
  1454.  
  1455.                 CloseIFF(Handle);
  1456.             }
  1457.  
  1458.             Close(Handle -> iff_Stream);
  1459.  
  1460.             if(!Success)
  1461.                 DeleteFile(Name);
  1462.         }
  1463.  
  1464.         FreeIFF(Handle);
  1465.     }
  1466.  
  1467.     return(Success);
  1468. }
  1469.  
  1470.     /* GetInches(STRPTR Buffer):
  1471.      *
  1472.      *    Turn a parameter string into a number representing
  1473.      *    a certain number of inches.
  1474.      */
  1475.  
  1476. float
  1477. GetInches(STRPTR Buffer)
  1478. {
  1479.     STATIC struct { STRPTR Unit; float Factor; } Units[7] =
  1480.     {
  1481.         "pt",    1.0,            /* Point */
  1482.         "pc",    12.0,            /* Pica */
  1483.         "in",    72.72,            /* Inch */
  1484.         "cm",    72.72 / 2.54,        /* Centimeter */
  1485.         "mm",    727.2 / 2.54,        /* Millimeter */
  1486.         "dd",    1157.0 / 1238.0,    /* Didot point */
  1487.         "cc",    1157.0 / 103.0        /* Cicero */
  1488.     };
  1489.  
  1490.     UBYTE    Temp[40];
  1491.     float    Value;
  1492.     LONG    i;
  1493.  
  1494.     i = 0;
  1495.  
  1496.         /* Strip the numeric part. */
  1497.  
  1498.     while((Buffer[i] >= '0' && Buffer[i] <= '9') || Buffer[i] == '.' || Buffer[i] == '+' || Buffer[i] == '-' || Buffer[i] == 'e')
  1499.     {
  1500.         Temp[i] = Buffer[i];
  1501.  
  1502.         i++;
  1503.     }
  1504.  
  1505.         /* Provide null-termination. */
  1506.  
  1507.     Temp[i] = 0;
  1508.  
  1509.         /* atof() appears to be broken in ixemul.library 39.45. */
  1510.  
  1511.     sscanf(Temp,"%f",&Value);
  1512.  
  1513.     Buffer += i;
  1514.  
  1515.         /* Which measuring unit? */
  1516.  
  1517.     for(i = 0 ; i < 7 ; i++)
  1518.     {
  1519.             /* Return the result in inches. */
  1520.  
  1521.         if(!Stricmp(Buffer,Units[i] . Unit))
  1522.             return(Value * Units[i] . Factor / 72.27);
  1523.     }
  1524.  
  1525.         /* Return the result in inches. */
  1526.  
  1527.     return(Value / 72.27);
  1528. }
  1529.  
  1530.     /* DispatchTask():
  1531.      *
  1532.      *    Asynchronous window message dispatcher.
  1533.      */
  1534.  
  1535. VOID
  1536. DispatchTask()
  1537. {
  1538.     struct Task    *me;
  1539.     gx_device    *dev;
  1540.  
  1541.         /* Set up global data area base register. */
  1542.  
  1543.     ix_geta4();
  1544.  
  1545.         /* Who am I? */
  1546.  
  1547.     me = FindTask(NULL);
  1548.  
  1549.         /* Wait for wakeup call. */
  1550.  
  1551.     Wait(SIG_HANDSHAKE);
  1552.  
  1553.         /* Obtain device pointer. */
  1554.  
  1555.     dev = me -> tc_UserData;
  1556.  
  1557.         /* Enable user input. */
  1558.  
  1559.     if(ModifyIDCMP(xdev -> window,IDCMP_FLAGS))
  1560.     {
  1561.         ULONG    Mask = 1 << xdev -> window -> UserPort -> mp_SigBit,
  1562.             Set;
  1563.         BOOL    Done = FALSE;
  1564.  
  1565.             /* Fill in the dispatcher entry. */
  1566.  
  1567.         xdev -> dispatcher = me;
  1568.  
  1569.             /* Ring back. */
  1570.  
  1571.         Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1572.  
  1573.             /* Wait for input... */
  1574.  
  1575.         do
  1576.         {
  1577.             Set = Wait(Mask | SIG_KILL);
  1578.  
  1579.             if(Set & Mask)
  1580.                 DispatchSuperWindow(dev);
  1581.  
  1582.             if(Set & SIG_KILL)
  1583.                 Done = TRUE;
  1584.         }
  1585.         while(!Done);
  1586.  
  1587.             /* Disable user input. */
  1588.  
  1589.         ModifyIDCMP(xdev -> window,NULL);
  1590.     }
  1591.  
  1592.         /* Disable task switching. */
  1593.  
  1594.     Forbid();
  1595.  
  1596.         /* Clear the dispatcher entry. */
  1597.  
  1598.     xdev -> dispatcher = NULL;
  1599.  
  1600.         /* Signal the main process that we are done. */
  1601.  
  1602.     Signal((struct Task *)xdev -> main,SIG_HANDSHAKE);
  1603.  
  1604.         /* Remove ourselves. */
  1605.  
  1606.     RemTask(NULL);
  1607. }
  1608.  
  1609.     /* DeleteScrollers(gx_device *dev):
  1610.      *
  1611.      *    Delete the window border scrollers.
  1612.      */
  1613.  
  1614. VOID
  1615. DeleteScrollers(gx_device *dev)
  1616. {
  1617.     if(xdev -> gadget)
  1618.     {
  1619.         if(xdev -> gadget[HORIZONTAL_SCROLLER])
  1620.             DisposeObject(xdev -> gadget[HORIZONTAL_SCROLLER]);
  1621.  
  1622.         if(xdev -> gadget[VERTICAL_SCROLLER])
  1623.             DisposeObject(xdev -> gadget[VERTICAL_SCROLLER]);
  1624.  
  1625.         if(xdev -> gadget[UP_ARROW])
  1626.             DisposeObject(xdev -> gadget[UP_ARROW]);
  1627.  
  1628.         if(xdev -> gadget[DOWN_ARROW])
  1629.             DisposeObject(xdev -> gadget[DOWN_ARROW]);
  1630.  
  1631.         if(xdev -> gadget[LEFT_ARROW])
  1632.             DisposeObject(xdev -> gadget[LEFT_ARROW]);
  1633.  
  1634.         if(xdev -> gadget[RIGHT_ARROW])
  1635.             DisposeObject(xdev -> gadget[RIGHT_ARROW]);
  1636.  
  1637.         FreeVec(xdev -> gadget);
  1638.  
  1639.         xdev -> gadget = NULL;
  1640.     }
  1641.  
  1642.     if(xdev -> image)
  1643.     {
  1644.         if(xdev -> image[UP_IMAGE])
  1645.             DisposeObject(xdev -> image[UP_IMAGE]);
  1646.  
  1647.         if(xdev -> image[DOWN_IMAGE])
  1648.             DisposeObject(xdev -> image[DOWN_IMAGE]);
  1649.  
  1650.         if(xdev -> image[LEFT_IMAGE])
  1651.             DisposeObject(xdev -> image[LEFT_IMAGE]);
  1652.  
  1653.         if(xdev -> image[RIGHT_IMAGE])
  1654.             DisposeObject(xdev -> image[RIGHT_IMAGE]);
  1655.  
  1656.         FreeVec(xdev -> image);
  1657.  
  1658.         xdev -> image = NULL;
  1659.     }
  1660. }
  1661.  
  1662.     /* CreateScrollers(gx_device *dev,struct Screen *Screen):
  1663.      *
  1664.      *    Create the window border scroller handles.
  1665.      */
  1666.  
  1667. BOOL
  1668. CreateScrollers(gx_device *dev,struct Screen *Screen)
  1669. {
  1670.     BOOL Result = FALSE;
  1671.  
  1672.     if(xdev -> gadget = (struct Gadget **)AllocVec(sizeof(struct Gadget *) * GADGET_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  1673.     {
  1674.         if(xdev -> image = (struct Image **)AllocVec(sizeof(struct Image *) * IMAGE_COUNT,MEMF_ANY | MEMF_CLEAR | MEMF_PUBLIC))
  1675.         {
  1676.             struct DrawInfo *DrawInfo;
  1677.  
  1678.             if(DrawInfo = GetScreenDrawInfo(Screen))
  1679.             {
  1680.                 LONG    SizeWidth,
  1681.                     SizeHeight;
  1682.                 UWORD    SizeType;
  1683.  
  1684.                 if(Screen -> Flags & SCREENHIRES)
  1685.                 {
  1686.                     SizeWidth    = 18;
  1687.                     SizeHeight    = 10;
  1688.  
  1689.                     SizeType    = SYSISIZE_MEDRES;
  1690.                 }
  1691.                 else
  1692.                 {
  1693.                     SizeWidth    = 13;
  1694.                     SizeHeight    = 11;
  1695.  
  1696.                     SizeType    = SYSISIZE_LOWRES;
  1697.                 }
  1698.  
  1699.                 if(xdev -> image[UP_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1700.                     SYSIA_Size,    SizeType,
  1701.                     SYSIA_Which,    UPIMAGE,
  1702.                     SYSIA_DrawInfo,    DrawInfo,
  1703.                 TAG_DONE))
  1704.                 {
  1705.                     if(xdev -> image[DOWN_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1706.                         SYSIA_Size,    SizeType,
  1707.                         SYSIA_Which,    DOWNIMAGE,
  1708.                         SYSIA_DrawInfo,    DrawInfo,
  1709.                     TAG_DONE))
  1710.                     {
  1711.                         if(xdev -> image[LEFT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1712.                             SYSIA_Size,    SizeType,
  1713.                             SYSIA_Which,    LEFTIMAGE,
  1714.                             SYSIA_DrawInfo,    DrawInfo,
  1715.                         TAG_DONE))
  1716.                         {
  1717.                             if(xdev -> image[RIGHT_IMAGE] = (struct Image *)NewObject(NULL,"sysiclass",
  1718.                                 SYSIA_Size,    SizeType,
  1719.                                 SYSIA_Which,    RIGHTIMAGE,
  1720.                                 SYSIA_DrawInfo,    DrawInfo,
  1721.                             TAG_DONE))
  1722.                             {
  1723.                                 if(xdev -> gadget[VERTICAL_SCROLLER] = NewObject(NULL,"propgclass",
  1724.                                     GA_ID,        VERTICAL_SCROLLER,
  1725.  
  1726.                                     GA_Top,        Screen -> WBorTop + Screen -> Font -> ta_YSize + 2,
  1727.                                     GA_RelHeight,    -(Screen -> WBorTop + Screen -> Font -> ta_YSize + 2 + SizeHeight + 1 + 2 * ARROW_HEIGHT),
  1728.                                     GA_Width,    SizeWidth - 8,
  1729.                                     GA_RelRight,    -(SizeWidth - 5),
  1730.  
  1731.                                     GA_GZZGadget,    TRUE,
  1732.                                     GA_Immediate,    TRUE,
  1733.                                     GA_FollowMouse,    TRUE,
  1734.                                     GA_RelVerify,    TRUE,
  1735.                                     GA_RightBorder,    TRUE,
  1736.  
  1737.                                     PGA_Freedom,    FREEVERT,
  1738.                                     PGA_NewLook,    TRUE,
  1739.                                     PGA_Borderless,    TRUE,
  1740.  
  1741.                                     PGA_Visible,    1,
  1742.                                     PGA_Total,    1,
  1743.                                 TAG_DONE))
  1744.                                 {
  1745.                                     if(xdev -> gadget[HORIZONTAL_SCROLLER] = NewObject(NULL,"propgclass",
  1746.                                         GA_ID,        HORIZONTAL_SCROLLER,
  1747.                                         GA_Previous,    xdev -> gadget[VERTICAL_SCROLLER],
  1748.  
  1749.                                         GA_Height,    SizeHeight - 4,
  1750.                                         GA_RelBottom,    -(SizeHeight - 4 + 1),
  1751.                                         GA_Left,    4,
  1752.                                         GA_RelWidth,    -(2 + SizeWidth + 4 + 2 * ARROW_WIDTH),
  1753.  
  1754.                                         GA_GZZGadget,    TRUE,
  1755.                                         GA_Immediate,    TRUE,
  1756.                                         GA_FollowMouse,    TRUE,
  1757.                                         GA_RelVerify,    TRUE,
  1758.                                         GA_BottomBorder,TRUE,
  1759.  
  1760.                                         PGA_Freedom,    FREEHORIZ,
  1761.                                         PGA_NewLook,    TRUE,
  1762.                                         PGA_Borderless,    TRUE,
  1763.  
  1764.                                         PGA_Visible,    1,
  1765.                                         PGA_Total,    1,
  1766.                                     TAG_DONE))
  1767.                                     {
  1768.                                         STATIC struct TagItem ArrowMappings[] = { GA_ID, GA_ID, TAG_END };
  1769.  
  1770.                                         if(xdev -> gadget[UP_ARROW] = NewObject(NULL,"buttongclass",
  1771.                                             GA_ID,        UP_ARROW,
  1772.                                             GA_Previous,    xdev -> gadget[HORIZONTAL_SCROLLER],
  1773.  
  1774.                                             GA_GZZGadget,    TRUE,
  1775.                                             GA_Image,    xdev -> image[UP_IMAGE],
  1776.                                             GA_RelRight,    -(SizeWidth - 1),
  1777.                                             GA_RelBottom,    -(SizeHeight - 1 + 2 * ARROW_HEIGHT),
  1778.                                             GA_Height,    ARROW_HEIGHT,
  1779.                                             GA_Width,    SizeWidth,
  1780.                                             GA_Immediate,    TRUE,
  1781.                                             GA_RelVerify,    TRUE,
  1782.                                             GA_RightBorder,    TRUE,
  1783.  
  1784.                                             ICA_TARGET,    ICTARGET_IDCMP,
  1785.                                             ICA_MAP,    ArrowMappings,
  1786.                                         TAG_DONE))
  1787.                                         {
  1788.                                             if(xdev -> gadget[DOWN_ARROW] = NewObject(NULL,"buttongclass",
  1789.                                                 GA_ID,        DOWN_ARROW,
  1790.                                                 GA_Previous,    xdev -> gadget[UP_ARROW],
  1791.  
  1792.                                                 GA_GZZGadget,    TRUE,
  1793.                                                 GA_Image,    xdev -> image[DOWN_IMAGE],
  1794.                                                 GA_RelRight,    -(SizeWidth - 1),
  1795.                                                 GA_RelBottom,    -(SizeHeight - 1 + ARROW_HEIGHT),
  1796.                                                 GA_Height,    ARROW_HEIGHT,
  1797.                                                 GA_Width,    SizeWidth,
  1798.                                                 GA_Immediate,    TRUE,
  1799.                                                 GA_RelVerify,    TRUE,
  1800.                                                 GA_RightBorder,    TRUE,
  1801.  
  1802.                                                 ICA_TARGET,    ICTARGET_IDCMP,
  1803.                                                 ICA_MAP,    ArrowMappings,
  1804.                                             TAG_DONE))
  1805.                                             {
  1806.                                                 if(xdev -> gadget[LEFT_ARROW] = NewObject(NULL,"buttongclass",
  1807.                                                     GA_ID,        LEFT_ARROW,
  1808.                                                     GA_Previous,    xdev -> gadget[DOWN_ARROW],
  1809.  
  1810.                                                     GA_GZZGadget,    TRUE,
  1811.                                                     GA_Image,    xdev -> image[LEFT_IMAGE],
  1812.                                                     GA_RelRight,    -(SizeWidth - 1 + 2 * ARROW_WIDTH),
  1813.                                                     GA_RelBottom,    -(SizeHeight - 1),
  1814.                                                     GA_Height,    SizeHeight,
  1815.                                                     GA_Width,    ARROW_WIDTH,
  1816.                                                     GA_Immediate,    TRUE,
  1817.                                                     GA_RelVerify,    TRUE,
  1818.                                                     GA_BottomBorder,TRUE,
  1819.  
  1820.                                                     ICA_TARGET,    ICTARGET_IDCMP,
  1821.                                                     ICA_MAP,    ArrowMappings,
  1822.                                                 TAG_DONE))
  1823.                                                 {
  1824.                                                     if(xdev -> gadget[RIGHT_ARROW] = NewObject(NULL,"buttongclass",
  1825.                                                         GA_ID,        RIGHT_ARROW,
  1826.                                                         GA_Previous,    xdev -> gadget[LEFT_ARROW],
  1827.  
  1828.                                                         GA_GZZGadget,    TRUE,
  1829.                                                         GA_Image,    xdev -> image[RIGHT_IMAGE],
  1830.                                                         GA_RelRight,    -(SizeWidth - 1 + ARROW_WIDTH),
  1831.                                                         GA_RelBottom,    -(SizeHeight - 1),
  1832.                                                         GA_Height,    SizeHeight,
  1833.                                                         GA_Width,    ARROW_WIDTH,
  1834.                                                         GA_Immediate,    TRUE,
  1835.                                                         GA_RelVerify,    TRUE,
  1836.                                                         GA_BottomBorder,TRUE,
  1837.  
  1838.                                                         ICA_TARGET,    ICTARGET_IDCMP,
  1839.                                                         ICA_MAP,    ArrowMappings,
  1840.                                                     TAG_DONE))
  1841.                                                         Result = TRUE;
  1842.                                                 }
  1843.                                             }
  1844.                                         }
  1845.                                     }
  1846.                                 }
  1847.                             }
  1848.                         }
  1849.                     }
  1850.                 }
  1851.  
  1852.                 FreeScreenDrawInfo(Screen,DrawInfo);
  1853.             }
  1854.         }
  1855.     }
  1856.  
  1857.     return(Result);
  1858. }
  1859.  
  1860.     /* WindowResize(gx_device *dev):
  1861.      *
  1862.      *    Update the slider sizes and positions after the window
  1863.      *    was resized.
  1864.      */
  1865.  
  1866. VOID
  1867. WindowResize(gx_device *dev)
  1868. {
  1869.     LONG    DeltaX,
  1870.         DeltaY,
  1871.         Temp;
  1872.  
  1873.         /* Query the current horizontal slider position. */
  1874.  
  1875.     if((Temp = LAYERXOFFSET(xdev -> window) + xdev -> window -> GZZWidth) > xdev -> super_width)
  1876.         DeltaX = xdev -> super_width - Temp;
  1877.     else
  1878.         DeltaX = 0;
  1879.  
  1880.         /* Query the current vertical slider position. */
  1881.  
  1882.     if((Temp = LAYERYOFFSET(xdev -> window) + xdev -> window -> GZZHeight) > xdev -> super_height)
  1883.         DeltaY = xdev -> super_height - Temp;
  1884.     else
  1885.         DeltaY = 0;
  1886.  
  1887.         /* Move the currently displayed window area around. */
  1888.  
  1889.     if(DeltaX || DeltaY)
  1890.         ScrollLayer(NULL,xdev -> window -> RPort -> Layer,DeltaX,DeltaY);
  1891.  
  1892.         /* Update the new horizontal slider position and size. */
  1893.  
  1894.     SetGadgetAttrs(xdev -> gadget[HORIZONTAL_SCROLLER],xdev -> window,NULL,
  1895.         PGA_Top,    LAYERXOFFSET(xdev -> window),
  1896.         PGA_Visible,    xdev -> window -> GZZWidth,
  1897.         PGA_Total,    xdev -> super_width,
  1898.     TAG_DONE);
  1899.  
  1900.         /* Update the new vertical slider position and size. */
  1901.  
  1902.     SetGadgetAttrs(xdev -> gadget[VERTICAL_SCROLLER],xdev -> window,NULL,
  1903.         PGA_Top,    LAYERYOFFSET(xdev -> window),
  1904.         PGA_Visible,    xdev -> window -> GZZHeight,
  1905.         PGA_Total,    xdev -> super_height,
  1906.     TAG_DONE);
  1907. }
  1908.  
  1909.     /* WindowUpdate(struct Gadget *Gadget,gx_device *dev):
  1910.      *
  1911.      *    Move the currently visible portion of the
  1912.      *    window according to the current slider
  1913.      *    position.
  1914.      */
  1915.  
  1916. VOID
  1917. WindowUpdate(struct Gadget *Gadget,gx_device *dev)
  1918. {
  1919.     LONG Storage;
  1920.  
  1921.     switch(Gadget -> GadgetID)
  1922.     {
  1923.         case HORIZONTAL_SCROLLER:
  1924.  
  1925.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1926.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  1927.  
  1928.             break;
  1929.  
  1930.         case VERTICAL_SCROLLER:
  1931.  
  1932.             if(GetAttr(PGA_Top,Gadget,&Storage))
  1933.                 ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  1934.  
  1935.             break;
  1936.     }
  1937. }
  1938.  
  1939.     /* MoveAround(struct Gadget *Gadget,int How,gx_device *dev):
  1940.      *
  1941.      *    Move the currently visible window area according to
  1942.      *    user input.
  1943.      */
  1944.  
  1945. VOID
  1946. MoveAround(struct Gadget *Gadget,LONG How,gx_device *dev)
  1947. {
  1948.     LONG Storage;
  1949.  
  1950.     if(GetAttr(PGA_Top,Gadget,&Storage))
  1951.     {
  1952.         LONG Max;
  1953.  
  1954.         switch(Gadget -> GadgetID)
  1955.         {
  1956.             case HORIZONTAL_SCROLLER:
  1957.  
  1958.                 Max = xdev -> super_width - xdev -> window -> GZZWidth;
  1959.                 break;
  1960.  
  1961.             case VERTICAL_SCROLLER:
  1962.  
  1963.                 Max = xdev -> super_height - xdev -> window -> GZZHeight;
  1964.                 break;
  1965.         }
  1966.  
  1967.         switch(How)
  1968.         {
  1969.             case MOVE_MIN:
  1970.  
  1971.                 Storage = 0;
  1972.                 break;
  1973.  
  1974.             case MOVE_MAX:
  1975.  
  1976.                 Storage = Max;
  1977.                 break;
  1978.  
  1979.             case MOVE_DOWN:
  1980.  
  1981.                 if(Storage > xdev -> super_height / 100)
  1982.                     Storage -= xdev -> super_height / 100;
  1983.                 else
  1984.                     Storage = 0;
  1985.  
  1986.                 break;
  1987.  
  1988.             case MOVE_FAR_DOWN:
  1989.  
  1990.                 if(Storage > xdev -> super_height / 10)
  1991.                     Storage -= xdev -> super_height / 10;
  1992.                 else
  1993.                     Storage = 0;
  1994.  
  1995.                 break;
  1996.  
  1997.             case MOVE_FAR_UP:
  1998.  
  1999.                 if(Storage + xdev -> super_width / 10 < Max)
  2000.                     Storage += xdev -> super_width / 10;
  2001.                 else
  2002.                     Storage = Max;
  2003.  
  2004.                 break;
  2005.  
  2006.             case MOVE_UP:
  2007.  
  2008.                 if(Storage + xdev -> super_width / 100 < Max)
  2009.                     Storage += xdev -> super_width / 100;
  2010.                 else
  2011.                     Storage = Max;
  2012.  
  2013.                 break;
  2014.         }
  2015.  
  2016.         switch(Gadget -> GadgetID)
  2017.         {
  2018.             case HORIZONTAL_SCROLLER:
  2019.  
  2020.                 if(LAYERXOFFSET(xdev -> window) != Storage)
  2021.                 {
  2022.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,Storage - LAYERXOFFSET(xdev -> window),0);
  2023.  
  2024.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2025.                         PGA_Top,Storage,
  2026.                     TAG_DONE);
  2027.                 }
  2028.  
  2029.                 break;
  2030.  
  2031.             case VERTICAL_SCROLLER:
  2032.  
  2033.                 if(LAYERYOFFSET(xdev -> window) != Storage)
  2034.                 {
  2035.                     ScrollLayer(NULL,xdev -> window -> RPort -> Layer,0,Storage - LAYERYOFFSET(xdev -> window));
  2036.  
  2037.                     SetGadgetAttrs(Gadget,xdev -> window,NULL,
  2038.                         PGA_Top,Storage,
  2039.                     TAG_DONE);
  2040.                 }
  2041.  
  2042.                 break;
  2043.         }
  2044.     }
  2045. }
  2046.  
  2047.     /* DispatchSuperWindow(gx_device *dev):
  2048.      *
  2049.      *    Dispatch user window input.
  2050.      */
  2051.  
  2052. VOID
  2053. DispatchSuperWindow(gx_device *dev)
  2054. {
  2055.     STATIC struct Gadget    *CurrentGadget = NULL;
  2056.  
  2057.     struct IntuiMessage    *IntuiMessage;
  2058.     ULONG             MsgClass,
  2059.                  MsgCode,
  2060.                  MsgQualifier;
  2061.     struct Gadget        *MsgGadget;
  2062.  
  2063.     while(IntuiMessage = (struct IntuiMessage *)GetMsg(xdev -> window -> UserPort))
  2064.     {
  2065.         MsgClass    = IntuiMessage -> Class;
  2066.         MsgCode        = IntuiMessage -> Code;
  2067.         MsgQualifier    = IntuiMessage -> Qualifier;
  2068.         MsgGadget    = IntuiMessage -> IAddress;
  2069.  
  2070.         ReplyMsg((struct Message *)IntuiMessage);
  2071.  
  2072.         switch(MsgClass)
  2073.         {
  2074.             case IDCMP_VANILLAKEY:
  2075.  
  2076.                 if(MsgCode == '\033' || MsgCode == '\003')
  2077.                     Signal((struct Task *)xdev -> main,SIG_KILL);
  2078.  
  2079.                 break;
  2080.  
  2081.             case IDCMP_RAWKEY:
  2082.  
  2083.                 switch(MsgCode)
  2084.                 {
  2085.                     case HELP_CODE:
  2086.  
  2087.                         DisplayBeep(xdev -> window -> WScreen);
  2088.  
  2089.                         break;
  2090.  
  2091.                     case CURSORUP:
  2092.  
  2093.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2094.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MIN,dev);
  2095.                         else
  2096.                         {
  2097.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2098.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2099.                             else
  2100.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2101.                         }
  2102.  
  2103.                         break;
  2104.  
  2105.                     case CURSORLEFT:
  2106.  
  2107.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2108.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MIN,dev);
  2109.                         else
  2110.                         {
  2111.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2112.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_DOWN,dev);
  2113.                             else
  2114.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2115.                         }
  2116.  
  2117.                         break;
  2118.  
  2119.                     case CURSORRIGHT:
  2120.  
  2121.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2122.                             MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_MAX,dev);
  2123.                         else
  2124.                         {
  2125.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2126.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_FAR_UP,dev);
  2127.                             else
  2128.                                 MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2129.                         }
  2130.  
  2131.                         break;
  2132.  
  2133.                     case CURSORDOWN:
  2134.  
  2135.                         if(MsgQualifier & IEQUALIFIER_CONTROL)
  2136.                             MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_MAX,dev);
  2137.                         else
  2138.                         {
  2139.                             if(MsgQualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  2140.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_FAR_UP,dev);
  2141.                             else
  2142.                                 MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2143.                         }
  2144.  
  2145.                         break;
  2146.  
  2147.                     default:
  2148.  
  2149.                         break;
  2150.                 }
  2151.  
  2152.                 break;
  2153.  
  2154.             case IDCMP_CLOSEWINDOW:
  2155.  
  2156.                 Signal((struct Task *)xdev -> main,SIG_KILL);
  2157.  
  2158.                 break;
  2159.  
  2160.             case IDCMP_GADGETDOWN:
  2161.  
  2162.                 CurrentGadget = MsgGadget;
  2163.  
  2164.                 WindowUpdate(MsgGadget,dev);
  2165.  
  2166.                 break;
  2167.  
  2168.             case IDCMP_GADGETUP:
  2169.  
  2170.                 CurrentGadget = NULL;
  2171.  
  2172.                 WindowUpdate(MsgGadget,dev);
  2173.  
  2174.                 break;
  2175.  
  2176.             case IDCMP_MOUSEMOVE:
  2177.  
  2178.                 if(CurrentGadget)
  2179.                     WindowUpdate(CurrentGadget,dev);
  2180.  
  2181.                 break;
  2182.  
  2183.             case IDCMP_IDCMPUPDATE:
  2184.  
  2185.                 switch(GetTagData(GA_ID,0,(struct TagItem *)MsgGadget))
  2186.                 {
  2187.                     case UP_ARROW:
  2188.  
  2189.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_DOWN,dev);
  2190.                         break;
  2191.  
  2192.                     case DOWN_ARROW:
  2193.  
  2194.                         MoveAround(xdev -> gadget[VERTICAL_SCROLLER],MOVE_UP,dev);
  2195.                         break;
  2196.  
  2197.                     case LEFT_ARROW:
  2198.  
  2199.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_DOWN,dev);
  2200.                         break;
  2201.  
  2202.                     case RIGHT_ARROW:
  2203.  
  2204.                         MoveAround(xdev -> gadget[HORIZONTAL_SCROLLER],MOVE_UP,dev);
  2205.                         break;
  2206.  
  2207.                     default:
  2208.  
  2209.                         break;
  2210.                 }
  2211.  
  2212.                 break;
  2213.  
  2214.             case IDCMP_NEWSIZE:
  2215.  
  2216.                 WindowResize(dev);
  2217.  
  2218.                 break;
  2219.  
  2220.             default:
  2221.  
  2222.                 break;
  2223.         }
  2224.     }
  2225. }
  2226.  
  2227.     /* Simple routine to call the cleanup routine of a device,
  2228.      * all devices are smart enough to handle shutdown in
  2229.      * case they have not been opened yet.
  2230.      */
  2231.  
  2232. STATIC void __inline
  2233. close_device(gx_device_amiga *dev)
  2234. {
  2235.     (*xdev -> procs -> close_device)((gx_device *)dev);
  2236. }
  2237.  
  2238.     /* devcleanup():
  2239.      *
  2240.      *    Clean up all devices, free all resources.
  2241.      */
  2242.  
  2243. void
  2244. devcleanup()
  2245. {
  2246.     close_device(&gs_amiga_device);
  2247.     close_device(&gs_amiga_low_device);
  2248.     close_device(&gs_amiga_high_device);
  2249.     close_device(&gs_amiga_super_device);
  2250.     close_device(&gs_amiga_a2024_device);
  2251.     close_device(&gs_amiga_printer_device);
  2252.     close_device(&gs_amiga_ilbm_device);
  2253. }
  2254.  
  2255.     /* amiga_set_pen(gx_device *dev,gx_color_index color):
  2256.      *
  2257.      *    Sets the rendering pen and remembers the current
  2258.      *    settings.
  2259.      */
  2260.  
  2261. STATIC VOID __inline
  2262. amiga_set_pen(gx_device *dev,gx_color_index color)
  2263. {
  2264.     if(xdev -> last_pen != color)
  2265.         SetAPen(xdev -> rport,xdev -> last_pen = color);
  2266. }
  2267.  
  2268.     /* amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  2269.      *
  2270.      *    Map a colour either to the black or the light rendering pen.
  2271.      */
  2272.  
  2273. gx_color_index
  2274. amiga_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  2275. {
  2276.     if((red | green | blue) > gx_max_color_value / 2)
  2277.         return(LightPen);
  2278.     else
  2279.         return(DarkPen);
  2280. }
  2281.  
  2282.     /* amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  2283.      *
  2284.      *    Map the light/dark rendering pen to RGB values.
  2285.      */
  2286.  
  2287. int
  2288. amiga_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  2289. {
  2290.     int i;
  2291.  
  2292.     if(color == LightPen)
  2293.     {
  2294.         for(i = 0 ; i < 3 ; i++)
  2295.             rgb[i] = gx_max_color_value;
  2296.     }
  2297.     else
  2298.     {
  2299.         for(i = 0 ; i < 3 ; i++)
  2300.             rgb[i] = 0;
  2301.     }
  2302.  
  2303.     return(0);
  2304. }
  2305.  
  2306.     /* AllocatePens(struct ViewPort *VPort,LONG CubeSize):
  2307.      *
  2308.      *    Allocate shareable viewport pens.
  2309.      */
  2310.  
  2311. LONG *
  2312. AllocatePens(struct ViewPort *VPort,LONG CubeSize)
  2313. {
  2314.     if(GfxBase -> LibNode . lib_Version >= 39)
  2315.     {
  2316.         LONG Total = CubeSize * CubeSize * CubeSize,*Pens;
  2317.  
  2318.         if(Pens = (LONG *)AllocVec(sizeof(LONG) * Total,MEMF_ANY))
  2319.         {
  2320.             LONG i,r,g,b,max = CubeSize - 1;
  2321.  
  2322.             for(i = 0 ; i < Total ; i++)
  2323.                 Pens[i] = -1;
  2324.  
  2325.             i = 0;
  2326.  
  2327.             for(r = 0 ; r < CubeSize ; r++)
  2328.             {
  2329.                 for(g = 0 ; g < CubeSize ; g++)
  2330.                 {
  2331.                     for(b = 0 ; b < CubeSize ; b++)
  2332.                     {
  2333.                         if((Pens[i++] = ObtainBestPen(VPort -> ColorMap,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max),
  2334.                             OBP_FailIfBad,    TRUE,
  2335.                             OBP_Precision,    PRECISION_IMAGE,
  2336.                         TAG_DONE)) == -1)
  2337.                         {
  2338.                             FreeVec(Pens);
  2339.  
  2340.                             return(NULL);
  2341.                         }
  2342.                     }
  2343.                 }
  2344.             }
  2345.  
  2346.             return(Pens);
  2347.         }
  2348.     }
  2349.  
  2350.     return(NULL);
  2351. }
  2352.  
  2353.     /* amiga_open_default(gx_device *dev):
  2354.      *
  2355.      *    Open the default device, i.e. a window on the Workbench screen.
  2356.      */
  2357.  
  2358. int
  2359. amiga_open_default(gx_device *dev)
  2360. {
  2361.     struct Screen *DefaultScreen;
  2362.  
  2363.         /* Get a lock on the default public screen. */
  2364.  
  2365.     if(DefaultScreen = LockPubScreen(NULL))
  2366.     {
  2367.         struct DisplayInfo    DisplayInfo;
  2368.         ULONG             Mode;
  2369.  
  2370.             /* Get the default public screen display mode. */
  2371.  
  2372.         Mode = GetVPModeID(&DefaultScreen -> ViewPort);
  2373.  
  2374.             /* Inquire display mode information. */
  2375.  
  2376.         if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode))
  2377.         {
  2378.             LONG    ScreenWidth,
  2379.                 ScreenHeight;
  2380.             LONG    i;
  2381.             float    Width,
  2382.                 Height;
  2383.             BOOL    GotMode = FALSE;
  2384.             LONG    Depth;
  2385.  
  2386.             if(GfxBase -> LibNode . lib_Version >= 39)
  2387.                 Depth = GetBitMapAttr(DefaultScreen -> RastPort . BitMap,BMA_DEPTH);
  2388.             else
  2389.                 Depth = DefaultScreen -> RastPort . BitMap -> Depth;
  2390.  
  2391.                 /* Determine screen view dimensions. */
  2392.  
  2393.             if(DefaultScreen -> ViewPort . ColorMap -> cm_vpe)
  2394.             {
  2395.                 struct ViewPortExtra *Extra = DefaultScreen -> ViewPort . ColorMap -> cm_vpe;
  2396.  
  2397.                 ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2398.                 ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2399.             }
  2400.             else
  2401.             {
  2402.                 struct ViewPortExtra *Extra;
  2403.  
  2404.                 if(Extra = (struct ViewPortExtra *)GfxLookUp(&DefaultScreen -> ViewPort))
  2405.                 {
  2406.                     ScreenWidth    = Extra -> DisplayClip . MaxX - Extra -> DisplayClip . MinX + 1;
  2407.                     ScreenHeight    = Extra -> DisplayClip . MaxY - Extra -> DisplayClip . MinY + 1;
  2408.                 }
  2409.                 else
  2410.                 {
  2411.                     ScreenWidth    = DefaultScreen -> Width;
  2412.                     ScreenHeight    = DefaultScreen -> Height;
  2413.                 }
  2414.             }
  2415.  
  2416.                 /* Determine the screen resolution. */
  2417.  
  2418.             for(i = 0 ; i < 4 ; i++)
  2419.             {
  2420.                 if((Mode & mode_dpi_table[i] . mode) == mode_dpi_table[i] . mode)
  2421.                 {
  2422.                     xdev -> x_pixels_per_inch = mode_dpi_table[i] . dpi;
  2423.                     xdev -> y_pixels_per_inch = (mode_dpi_table[i] . dpi * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  2424.  
  2425.                     GotMode = TRUE;
  2426.  
  2427.                     break;
  2428.                 }
  2429.             }
  2430.  
  2431.                 /* Use the best guess, we will take the standard
  2432.                  * low resolution x-dpi value and scale it by
  2433.                  * the pixel speed.
  2434.                  */
  2435.  
  2436.             if(!GotMode && DisplayInfo . PixelSpeed)
  2437.             {
  2438.                 xdev -> x_pixels_per_inch = (35.0 * 140.0) / (float)DisplayInfo . PixelSpeed;
  2439.                 xdev -> y_pixels_per_inch = (xdev -> x_pixels_per_inch * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  2440.             }
  2441.  
  2442.             if(xdev -> width > 0 && xdev -> height > 0)
  2443.             {
  2444.                 xdev -> super_width    = xdev -> width;
  2445.                 xdev -> super_height    = xdev -> height;
  2446.             }
  2447.             else
  2448.             {
  2449.                 if(xdev -> page_width > 0.0)
  2450.                     xdev -> super_width = (LONG)(xdev -> page_width * xdev -> x_pixels_per_inch);
  2451.                 else
  2452.                     xdev -> super_width = 640;
  2453.  
  2454.                 if(xdev -> page_height > 0.0)
  2455.                     xdev -> super_height = (LONG)(xdev -> page_height * xdev -> y_pixels_per_inch);
  2456.                 else
  2457.                     xdev -> super_height = 512;
  2458.             }
  2459.  
  2460.                 /* Allocate a bitmap ready to be used for
  2461.                  * rendering.
  2462.                  */
  2463.  
  2464.             if(xdev -> super_bitmap = CreateBitMap(xdev -> super_width,xdev -> super_height,Depth,BMF_DISPLAYABLE,DefaultScreen -> RastPort . BitMap,FALSE))
  2465.             {
  2466.                     /* Clear the bitplanes. */
  2467.  
  2468.                 BltBitMap(xdev -> super_bitmap,0,0,xdev -> super_bitmap,0,0,xdev -> super_width,xdev -> super_height,0x00,(1 << xdev -> super_bitmap -> Depth) - 1,NULL);
  2469.  
  2470.                     /* Create the scroller handles. */
  2471.  
  2472.                 if(CreateScrollers(dev,DefaultScreen))
  2473.                 {
  2474.                     struct IBox ZoomBox;
  2475.  
  2476.                         /* Set up the window alternate
  2477.                          * position.
  2478.                          */
  2479.  
  2480.                     ZoomBox . Left        = 0;
  2481.                     ZoomBox . Top        = DefaultScreen -> BarHeight + 1;
  2482.                     ZoomBox . Width        = ScreenWidth;
  2483.                     ZoomBox . Height    = ScreenHeight - ZoomBox . Top;
  2484.  
  2485.                         /* Eventually, open the display window. */
  2486.  
  2487.                     if(xdev -> window = OpenWindowTags(NULL,
  2488.                         WA_InnerWidth,        MIN(DefaultScreen -> Width / 2,xdev -> super_width),
  2489.                         WA_InnerHeight,        MIN(DefaultScreen -> Height / 2,xdev -> super_height),
  2490.                         WA_CloseGadget,        TRUE,
  2491.                         WA_DepthGadget,        TRUE,
  2492.                         WA_SizeGadget,        TRUE,
  2493.                         WA_SizeBRight,        TRUE,
  2494.                         WA_SizeBBottom,        TRUE,
  2495.                         WA_Zoom,        &ZoomBox,
  2496.                         WA_DragBar,        TRUE,
  2497.                         WA_NoCareRefresh,    TRUE,
  2498.                         WA_GimmeZeroZero,    TRUE,
  2499.                         WA_RMBTrap,        TRUE,
  2500.                         WA_SuperBitMap,        xdev -> super_bitmap,
  2501.                         WA_Gadgets,        xdev -> gadget[VERTICAL_SCROLLER],
  2502.                         WA_CustomScreen,    DefaultScreen,
  2503.                         WA_Title,        "Ghostscript Amiga output window",
  2504.                     TAG_DONE))
  2505.                     {
  2506.                         if(xdev -> temp_rport = CreateTempRPort(xdev -> window -> RPort))
  2507.                         {
  2508.                             if(xdev -> temp_array = (UBYTE *)AllocVec(xdev -> window -> WScreen -> Width,MEMF_ANY))
  2509.                             {
  2510.                                 struct Task *Task;
  2511.  
  2512.                                     /* Bring the window dispatcher task
  2513.                                      * to life...
  2514.                                      */
  2515.  
  2516.                                 if(Task = (struct Task *)CreateTask("Ghostscript window dispatcher",5,DispatchTask,8192))
  2517.                                 {
  2518.                                     const sigset_t trapped = sigmask(SIGINT);
  2519.  
  2520.                                         /* Cheap... */
  2521.  
  2522.                                     Task -> tc_UserData = dev;
  2523.  
  2524.                                         /* Who's calling? */
  2525.  
  2526.                                     xdev -> main = (struct Process *)FindTask(NULL);
  2527.  
  2528.                                         /* Don't let anybody interrupt us! */
  2529.  
  2530.                                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2531.  
  2532.                                     Forbid();
  2533.  
  2534.                                         /* Wake it up. */
  2535.  
  2536.                                     Signal(Task,SIG_HANDSHAKE);
  2537.  
  2538.                                         /* Clear the handshake bit. */
  2539.  
  2540.                                     SetSignal(0,SIG_HANDSHAKE);
  2541.  
  2542.                                         /* Wait for the report. */
  2543.  
  2544.                                     Wait(SIG_HANDSHAKE);
  2545.  
  2546.                                     Permit();
  2547.  
  2548.                                         /* Get the result. */
  2549.  
  2550.                                     Task = xdev -> dispatcher;
  2551.  
  2552.                                         /* Unblock signals. */
  2553.  
  2554.                                     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2555.                                 }
  2556.  
  2557.                                     /* Did we succeed in creating
  2558.                                      * the dispatcher task?
  2559.                                      */
  2560.  
  2561.                                 if(Task)
  2562.                                 {
  2563.                                     UWORD    MaxValue    = 0,
  2564.                                         MinValue    = 15000,
  2565.                                         Value,
  2566.                                         R,G,B;
  2567.  
  2568.                                         /* Set the window limits. */
  2569.  
  2570.                                     WindowLimits(xdev -> window,xdev -> window -> BorderLeft + MINIMUM_WIDTH + xdev -> window -> BorderRight,xdev -> window -> BorderTop + MINIMUM_HEIGHT + xdev -> window -> BorderBottom,xdev -> window -> BorderLeft + xdev -> super_width + xdev -> window -> BorderRight,xdev -> window -> BorderTop + xdev -> super_height + xdev -> window -> BorderBottom);
  2571.  
  2572.                                         /* Update the sliders. */
  2573.  
  2574.                                     WindowResize(dev);
  2575.  
  2576.                                         /* Look for the darkest and the lightest screen colours. */
  2577.  
  2578.                                     for(i = 0 ; i < MIN(xdev -> window -> WScreen -> ViewPort . ColorMap -> Count,(1 << Depth)) ; i++)
  2579.                                     {
  2580.                                         Value = GetRGB4(xdev -> window -> WScreen -> ViewPort . ColorMap,i);
  2581.  
  2582.                                         R = (Value >> 8) & 0xF;
  2583.                                         G = (Value >> 4) & 0xF;
  2584.                                         B =  Value       & 0xF;
  2585.  
  2586.                                             /* Luminance conversion included */
  2587.  
  2588.                                         Value = R * 299 + G * 588 + B * 113;
  2589.  
  2590.                                         if(Value > MaxValue)
  2591.                                         {
  2592.                                             MaxValue = Value;
  2593.  
  2594.                                             LightPen = i;
  2595.                                         }
  2596.  
  2597.                                         if(Value < MinValue)
  2598.                                         {
  2599.                                             MinValue = Value;
  2600.  
  2601.                                             DarkPen = i;
  2602.                                         }
  2603.                                     }
  2604.  
  2605.                                         /* Fill in the rest. */
  2606.  
  2607.                                     xdev -> width    = xdev -> super_width;
  2608.                                     xdev -> height    = xdev -> super_height;
  2609.                                     xdev -> rport    = xdev -> window -> RPort;
  2610.  
  2611.                                         /* Does the display support
  2612.                                          * at least eight colours?
  2613.                                          */
  2614.  
  2615.                                     if(Depth >= 3)
  2616.                                     {
  2617.                                         LONG cube_size,max;
  2618.  
  2619.                                             /* Set up a fitting colour cube. */
  2620.  
  2621.                                         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  2622.                                         {
  2623.                                             if((max = cube_size * cube_size * cube_size) <= 1 << Depth)
  2624.                                                 break;
  2625.                                         }
  2626.  
  2627.                                             /* Got enough colours? */
  2628.  
  2629.                                         if(cube_size != 1)
  2630.                                         {
  2631.                                             LONG *Pens;
  2632.  
  2633.                                                 /* Try to grab the cube colours,
  2634.                                                  * making a colour display.
  2635.                                                  */
  2636.  
  2637.                                             if(Pens = AllocatePens(&xdev -> window -> WScreen -> ViewPort,cube_size))
  2638.                                                 set_colour_device((gx_device_amiga *)dev,cube_size,Pens);
  2639.                                         }
  2640.                                     }
  2641.  
  2642.                                     SetBPen(xdev -> rport,0);
  2643.                                     SetDrMd(xdev -> rport,JAM2);
  2644.  
  2645.                                     amiga_set_pen(dev,DarkPen);
  2646.  
  2647.                                     UnlockPubScreen(NULL,DefaultScreen);
  2648.  
  2649.                                     return(0);
  2650.                                 }
  2651.                                 else
  2652.                                     perror("Ghostscript: failed to create dispatcher task");
  2653.                             }
  2654.                             else
  2655.                                 perror("Ghostscript: failed to create temporary line buffer.");
  2656.                         }
  2657.                         else
  2658.                             perror("Ghostscript: failed to create temporary raster port");
  2659.                     }
  2660.                     else
  2661.                         perror("Ghostscript: failed to open window");
  2662.                 }
  2663.                 else
  2664.                     perror("Ghostscript: failed to allocate scrollers");
  2665.             }
  2666.             else
  2667.                 perror("Ghostscript: failed to allocate bitmap");
  2668.         }
  2669.         else
  2670.             perror("Ghostscript: failed to get display mode information");
  2671.  
  2672.         UnlockPubScreen(NULL,DefaultScreen);
  2673.     }
  2674.     else
  2675.         perror("Ghostscript: failed to lock default public screen");
  2676.  
  2677.     return(-1);
  2678. }
  2679.  
  2680.     /* amiga_open_low(gx_device *dev):
  2681.      *
  2682.      *    Open the low resolution device.
  2683.      */
  2684.  
  2685. int
  2686. amiga_open_low(gx_device *dev)
  2687. {
  2688.     return(amiga_open(dev,LORES_KEY));
  2689. }
  2690.  
  2691.     /* amiga_open_high(gx_device *dev):
  2692.      *
  2693.      *    Open the high resolution device.
  2694.      */
  2695.  
  2696. int
  2697. amiga_open_high(gx_device *dev)
  2698. {
  2699.     return(amiga_open(dev,HIRESLACE_KEY));
  2700. }
  2701.  
  2702.     /* amiga_open_super(gx_device *dev):
  2703.      *
  2704.      *    Open the super high resolution device.
  2705.      */
  2706.  
  2707. int
  2708. amiga_open_super(gx_device *dev)
  2709. {
  2710.         /* Fall back to the default if not available. */
  2711.  
  2712.     if(ModeNotAvailable(SUPERLACE_KEY))
  2713.         return(amiga_open_high(dev));
  2714.     else
  2715.         return(amiga_open(dev,SUPERLACE_KEY));
  2716. }
  2717.  
  2718.     /* amiga_open_a2024(gx_device *dev):
  2719.      *
  2720.      *    Open the A2024 device.
  2721.      */
  2722.  
  2723. int
  2724. amiga_open_a2024(gx_device *dev)
  2725. {
  2726.         /* Fall back to the default if not available. */
  2727.  
  2728.     if(ModeNotAvailable(A2024TENHERTZ_KEY))
  2729.         return(amiga_open_super(dev));
  2730.     else
  2731.         return(amiga_open(dev,A2024TENHERTZ_KEY));
  2732.  
  2733. /*    if(ModeNotAvailable(0xF1004))*/
  2734. /*        return(amiga_open_high(dev));*/
  2735. /*    else*/
  2736. /*        return(amiga_open(dev,0xF1004));*/
  2737. }
  2738.  
  2739.     /* amiga_open_printer(gx_device *dev):
  2740.      *
  2741.      *    Open the printer device.
  2742.      */
  2743.  
  2744. int
  2745. amiga_open_printer(gx_device *dev)
  2746. {
  2747.     if(xdev -> port = CreateMsgPort())
  2748.     {
  2749.         if(xdev -> printer = (struct IODRPReq *)CreateIORequest(xdev -> port,sizeof(struct IODRPReq)))
  2750.         {
  2751.             if(!OpenDevice("printer.device",0,(struct IORequest *)xdev -> printer,0))
  2752.             {
  2753.                 if(xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  2754.                 {
  2755.                     const sigset_t    trapped = sigmask(SIGINT);
  2756.                     struct BitMap    DummyBitMap;
  2757.                     UWORD        DummyLine[12];
  2758.  
  2759.                     InitRastPort(xdev -> rport);
  2760.  
  2761.                         /* Cook up a dummy bitmap to keep
  2762.                          * `smart' drivers from complaining.
  2763.                          */
  2764.  
  2765.                     InitBitMap(&DummyBitMap,12,16,1);
  2766.  
  2767.                     DummyBitMap . Planes[0] = (PLANEPTR)&DummyLine;
  2768.  
  2769.                     xdev -> rport -> BitMap = &DummyBitMap;
  2770.  
  2771.                         /* Query page size requirements. */
  2772.  
  2773.                     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  2774.                     xdev -> printer -> io_RastPort    = xdev -> rport;
  2775.                     xdev -> printer -> io_ColorMap    = xdev -> colormap;
  2776.                     xdev -> printer -> io_SrcWidth    = 16;
  2777.                     xdev -> printer -> io_SrcHeight    = 1;
  2778.                     xdev -> printer -> io_DestCols    = 0;
  2779.                     xdev -> printer -> io_DestRows    = 0;
  2780.  
  2781.                     xdev -> printer -> io_Special |= SPECIAL_NOPRINT;
  2782.  
  2783.                         /* Don't let them stop us now! */
  2784.  
  2785.                     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2786.  
  2787.                         /* Ask for it... */
  2788.  
  2789.                     if(!DoIO((struct IORequest *)xdev -> printer))
  2790.                     {
  2791.                         struct PrinterExtendedData    *PED;
  2792.                         struct PrinterData        *PD;
  2793.                         LONG                 Depth,
  2794.                                          NumColours,
  2795.                                          CubeSize;
  2796.  
  2797.                             /* Unblock ^C signal. */
  2798.  
  2799.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2800.  
  2801.                             /* Get the printer internal data. */
  2802.  
  2803.                         PD    = (struct PrinterData *)xdev -> printer -> io_Device;
  2804.                         PED    = &PD -> pd_SegmentData -> ps_PED;
  2805.  
  2806.                             /* Set up the default colour values. */
  2807.  
  2808.                         if(PD -> pd_Preferences . PrintShade == SHADE_BW)
  2809.                         {
  2810.                             Depth        = 1;
  2811.                             NumColours    = 2;
  2812.                             CubeSize    = 0;
  2813.                         }
  2814.                         else
  2815.                         {
  2816.                             Depth        = 12;
  2817.                             NumColours    = 4096;
  2818.                             CubeSize    = 16;
  2819.                         }
  2820.  
  2821.                             /* Get the page size */
  2822.  
  2823.                         if(xdev -> width > 0 && xdev -> height > 0)
  2824.                         {
  2825.                             if(PED -> ped_MaxXDots < xdev -> width)
  2826.                                 xdev -> width = PED -> ped_MaxXDots;
  2827.  
  2828.                             if(PED -> ped_MaxYDots < xdev -> height)
  2829.                                 xdev -> height = PED -> ped_MaxYDots;
  2830.                         }
  2831.                         else
  2832.                         {
  2833.                             xdev -> width    = PED -> ped_MaxXDots;
  2834.                             xdev -> height    = PED -> ped_MaxYDots;
  2835.                         }
  2836.  
  2837.                             /* Get the DPI values */
  2838.  
  2839.                         xdev -> x_pixels_per_inch    = (float)PED -> ped_XDotsInch;
  2840.                         xdev -> y_pixels_per_inch    = (float)PED -> ped_YDotsInch;
  2841.  
  2842.                             /* Try to allocate a suitable bitmap.
  2843.                              * If an allocation fails, rescale the
  2844.                              * colour cube and bitmap depth and
  2845.                              * retry. Minimum are eight colours.
  2846.                              */
  2847.  
  2848.                         do
  2849.                         {
  2850.                                 /* Try to allocate the raster... */
  2851.  
  2852.                             if(!(xdev -> bitmap = CreateBitMap(xdev -> width,xdev -> height,Depth,NULL,NULL,TRUE)))
  2853.                             {
  2854.                                     /* Any chance to rescale the cube? */
  2855.  
  2856.                                 if(Depth < 2)
  2857.                                     break;
  2858.                                 else
  2859.                                 {
  2860.                                         /* One plane less... */
  2861.  
  2862.                                     Depth--;
  2863.  
  2864.                                         /* Rescale the cube. */
  2865.  
  2866.                                     while(CubeSize >= 2)
  2867.                                     {
  2868.                                         if((NumColours = CubeSize * CubeSize * CubeSize) <= (1 << Depth))
  2869.                                             break;
  2870.                                         else
  2871.                                             CubeSize--;
  2872.                                     }
  2873.  
  2874.                                         /* Less than eight colours? */
  2875.  
  2876.                                     if(CubeSize < 2)
  2877.                                         break;
  2878.                                 }
  2879.                             }
  2880.                         }
  2881.                         while(!xdev -> bitmap);
  2882.  
  2883.                             /* Got the bitmap? */
  2884.  
  2885.                         if(xdev -> bitmap)
  2886.                         {
  2887.                                 /* Allocate a suitable colour map. */
  2888.  
  2889.                             if(xdev -> colormap = GetColorMap(NumColours))
  2890.                             {
  2891.                                     /* Black & white only? */
  2892.  
  2893.                                 if(NumColours == 2)
  2894.                                 {
  2895.                                     SetRGB4CM(xdev -> colormap,0,0x0,0x0,0x0);
  2896.                                     SetRGB4CM(xdev -> colormap,1,0xF,0xF,0xF);
  2897.                                 }
  2898.                                 else
  2899.                                 {
  2900.                                     LONG i = 0,r,g,b,max = CubeSize - 1;
  2901.  
  2902.                                         /* Fill in the colour cube. */
  2903.  
  2904.                                     for(r = 0 ; r < CubeSize ; r++)
  2905.                                     {
  2906.                                         for(g = 0 ; g < CubeSize ; g++)
  2907.                                         {
  2908.                                             for(b = 0 ; b < CubeSize ; b++)
  2909.                                                 SetRGB4CM(xdev -> colormap,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  2910.                                         }
  2911.                                     }
  2912.  
  2913.                                     set_colour_printer_device((gx_device_amiga *)dev,CubeSize);
  2914.                                 }
  2915.  
  2916.                                 xdev -> rport -> BitMap = xdev -> bitmap;
  2917.  
  2918.                                 return(0);
  2919.                             }
  2920.                             else
  2921.                                 perror("Ghostscript: failed to allocate colour map");
  2922.                         }
  2923.                         else
  2924.                         {
  2925.                             char buffer[256];
  2926.  
  2927.                             sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %ld, largest %ld)",(xdev -> width + 15) / 8 * xdev -> height * Depth,AvailMem(MEMF_ANY | MEMF_LARGEST));
  2928.  
  2929.                             perror(buffer);
  2930.                         }
  2931.                     }
  2932.                     else
  2933.                     {
  2934.                         char buffer[256];
  2935.  
  2936.                         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  2937.  
  2938.                         sprintf(buffer,"Ghostscript: failed to query printer page size (error code #%ld)",xdev -> printer -> io_Error);
  2939.  
  2940.                         perror(buffer);
  2941.                     }
  2942.                 }
  2943.                 else
  2944.                     perror("Ghostscript: failed to allocate raster port");
  2945.             }
  2946.             else
  2947.             {
  2948.                 char buffer[256];
  2949.  
  2950.                 sprintf(buffer,"Ghostscript: failed to open printer.device (error code #%ld)",xdev -> printer -> io_Error);
  2951.  
  2952.                 perror(buffer);
  2953.             }
  2954.         }
  2955.         else
  2956.             perror("Ghostscript: failed to allocate device driver");
  2957.     }
  2958.     else
  2959.         perror("Ghostscript: failed to create io port");
  2960.  
  2961.     return(-1);
  2962. }
  2963.  
  2964.     /* amiga_output_page_printer(gx_device *dev,int,int):
  2965.      *
  2966.      *    Send a bitmap to the printer.
  2967.      */
  2968.  
  2969. int
  2970. amiga_output_page_printer(gx_device *dev,int num_copies,int flush)
  2971. {
  2972.     const sigset_t trapped = sigmask(SIGINT);
  2973.     int result,i;
  2974.  
  2975.     xdev -> printer -> io_Command    = PRD_DUMPRPORT;
  2976.     xdev -> printer -> io_SrcWidth    = xdev -> width;
  2977.     xdev -> printer -> io_SrcHeight    = xdev -> height;
  2978.     xdev -> printer -> io_DestCols    = xdev -> width;
  2979.     xdev -> printer -> io_DestRows    = xdev -> height;
  2980.  
  2981.     xdev -> printer -> io_Special &= ~SPECIAL_NOPRINT;
  2982.  
  2983.         /* We cannot possibly allow being interrupted in the middle
  2984.          * of a raster dump!
  2985.          */
  2986.  
  2987.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  2988.  
  2989.     for(i = 0 ; i < num_copies ; i++)
  2990.     {
  2991.         if(DoIO((struct IORequest *)xdev -> printer))
  2992.         {
  2993.             char buffer[256];
  2994.  
  2995.             sprintf(buffer,"Ghostscript: failed to print raster (error code #%ld)",xdev -> printer -> io_Error);
  2996.  
  2997.             perror(buffer);
  2998.  
  2999.             result = -1;
  3000.  
  3001.             break;
  3002.         }
  3003.         else
  3004.             result = 0;
  3005.     }
  3006.  
  3007.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3008.  
  3009.     return(result);
  3010. }
  3011.  
  3012.     /* amiga_close_printer(gx_device *dev):
  3013.      *
  3014.      *    Close the printer driver.
  3015.      */
  3016.  
  3017. int
  3018. amiga_close_printer(gx_device *dev)
  3019. {
  3020.     if(xdev -> bitmap)
  3021.     {
  3022.         DeleteBitMap(xdev -> bitmap,TRUE);
  3023.  
  3024.         xdev -> bitmap = NULL;
  3025.     }
  3026.  
  3027.     if(xdev -> rport)
  3028.     {
  3029.         FreeVec(xdev -> rport);
  3030.  
  3031.         xdev -> rport = NULL;
  3032.     }
  3033.  
  3034.     if(xdev -> colormap)
  3035.     {
  3036.         FreeColorMap(xdev -> colormap);
  3037.  
  3038.         xdev -> colormap = NULL;
  3039.     }
  3040.  
  3041.     if(xdev -> printer)
  3042.     {
  3043.         if(xdev -> printer -> io_Device)
  3044.             CloseDevice((struct IORequest *)xdev -> printer);
  3045.  
  3046.         DeleteIORequest(xdev -> printer);
  3047.  
  3048.         xdev -> printer = NULL;
  3049.     }
  3050.  
  3051.     if(xdev -> port)
  3052.     {
  3053.         DeleteMsgPort(xdev -> port);
  3054.  
  3055.         xdev -> port = NULL;
  3056.     }
  3057.  
  3058.     xdev -> width = xdev -> height = 0;
  3059. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  3060.  
  3061.     return(0);
  3062. }
  3063.  
  3064.     /* amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data):
  3065.      *
  3066.      *    Read the raster bits into a buffer.
  3067.      */
  3068.  
  3069. int
  3070. amiga_get_bits(gx_device *dev,int y,byte *str,byte **actual_data)
  3071. {
  3072.     if(y < 0 || y > xdev -> height)
  3073.         return(-1);
  3074.     else
  3075.     {
  3076.         if(actual_data)
  3077.             *actual_data = (byte *)(xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y);
  3078.         else
  3079.             memcpy(str,xdev -> bitmap -> Planes[0] + xdev -> bitmap -> BytesPerRow * y,xdev -> bitmap -> BytesPerRow);
  3080.  
  3081.         return(0);
  3082.     }
  3083. }
  3084.  
  3085.     /* amiga_open(gx_device *dev,ULONG Mode):
  3086.      *
  3087.      *    Open a custom screen.
  3088.      */
  3089.  
  3090. int
  3091. amiga_open(gx_device *dev,ULONG Mode)
  3092. {
  3093.     struct DisplayInfo    DisplayInfo;
  3094.     struct DimensionInfo    DimensionInfo;
  3095.  
  3096.         /* Get the display dimensions. */
  3097.  
  3098.     if(GetDisplayInfoData(NULL,(APTR)&DisplayInfo,sizeof(struct DisplayInfo),DTAG_DISP,Mode) && GetDisplayInfoData(NULL,(APTR)&DimensionInfo,sizeof(struct DimensionInfo),DTAG_DIMS,Mode))
  3099.     {
  3100.             /* Two shades only, black & white */
  3101.  
  3102.         STATIC struct ColorSpec Colours[] =
  3103.         {
  3104.              0,    0x0000, 0x0000, 0x0000,
  3105.              1,    0xFFFF, 0xFFFF, 0xFFFF,
  3106.  
  3107.             -1
  3108.         };
  3109.  
  3110.         float    Width,
  3111.             Height;
  3112.         LONG    i,cube_size,max;
  3113.         LONG    ScreenWidth,
  3114.             ScreenHeight,
  3115.             ScreenDepth;
  3116.         BOOL    GotMode = FALSE;
  3117.  
  3118.             /* Start up with a maximum depth display. */
  3119.  
  3120.         ScreenDepth = DimensionInfo . MaxDepth;
  3121.  
  3122.             /* Check to see whether we will be able to
  3123.              * build a colour display or not.
  3124.              */
  3125.  
  3126.         for(cube_size = 6 ; cube_size >= 2 ; cube_size--)
  3127.         {
  3128.             if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3129.                 break;
  3130.         }
  3131.  
  3132.             /* Got enough colours? */
  3133.  
  3134.         if(cube_size != 1)
  3135.             set_colour_device((gx_device_amiga *)dev,cube_size,NULL);
  3136.         else
  3137.         {
  3138.             ScreenDepth = 1;
  3139.  
  3140.             set_mono_device((gx_device_amiga *)dev);
  3141.         }
  3142.  
  3143.         if(xdev -> width > 0 && xdev -> height > 0)
  3144.         {
  3145.             Width    = xdev -> width;
  3146.             Height    = xdev -> height;
  3147.         }
  3148.         else
  3149.         {
  3150.             if(xdev -> page_width > 0.0)
  3151.                 Width = xdev -> page_width;
  3152.             else
  3153.                 Width = 0.0;
  3154.  
  3155.             if(xdev -> page_height > 0.0)
  3156.                 Height = xdev -> page_height;
  3157.             else
  3158.                 Height = 0.0;
  3159.         }
  3160.  
  3161.             /* Determine screen resolution */
  3162.  
  3163.         for(i = 0 ; i < 4 ; i++)
  3164.         {
  3165.             if((Mode & mode_dpi_table[i] . mode) == mode_dpi_table[i] . mode)
  3166.             {
  3167.                 xdev -> x_pixels_per_inch = mode_dpi_table[i] . dpi;
  3168.                 xdev -> y_pixels_per_inch = (mode_dpi_table[i] . dpi * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  3169.  
  3170.                 GotMode = TRUE;
  3171.  
  3172.                 break;
  3173.             }
  3174.         }
  3175.  
  3176.             /* Use the best guess, we will take the standard
  3177.              * low resolution x-dpi value and scale it by
  3178.              * the pixel speed.
  3179.              */
  3180.  
  3181.         if(!GotMode && DisplayInfo . PixelSpeed)
  3182.         {
  3183.             xdev -> x_pixels_per_inch = (35.0 * 140.0) / (float)DisplayInfo . PixelSpeed;
  3184.             xdev -> y_pixels_per_inch = (xdev -> x_pixels_per_inch * (float)DisplayInfo . Resolution . x) / (float)DisplayInfo . Resolution . y;
  3185.         }
  3186.  
  3187.         if(Width > 0.0)
  3188.             ScreenWidth = (LONG)(Width * xdev -> x_pixels_per_inch);
  3189.         else
  3190.             ScreenWidth = 0;
  3191.  
  3192.         if(Height > 0.0)
  3193.             ScreenHeight = (LONG)(Height * xdev -> y_pixels_per_inch);
  3194.         else
  3195.             ScreenHeight = 0;
  3196.  
  3197.         if(ScreenWidth < DimensionInfo . MinRasterWidth || ScreenWidth > DimensionInfo . MaxRasterWidth)
  3198.             ScreenWidth = 0;
  3199.  
  3200.         if(ScreenHeight < DimensionInfo . MinRasterHeight || ScreenHeight > DimensionInfo . MaxRasterHeight)
  3201.             ScreenHeight = 0;
  3202.  
  3203.             /* Try to open a custom screen; if this fails, try to
  3204.              * rescale the colour cube and retry.
  3205.              */
  3206.  
  3207.         do
  3208.         {
  3209.             if(!(xdev -> screen = OpenScreenTags(NULL,
  3210.                 SA_Depth,    ScreenDepth,
  3211.                 SA_Overscan,    OSCAN_TEXT,
  3212.                 SA_Quiet,    TRUE,
  3213.                 SA_Behind,    TRUE,
  3214.                 SA_DisplayID,    Mode,
  3215.                 SA_Colors,    Colours,
  3216.                 SA_AutoScroll,    TRUE,
  3217.                 SA_ShowTitle,    FALSE,
  3218.  
  3219.                 ScreenWidth  > 0 ? SA_Width  : TAG_IGNORE,    ScreenWidth,
  3220.                 ScreenHeight > 0 ? SA_Height : TAG_IGNORE,    ScreenHeight,
  3221.             TAG_DONE)))
  3222.             {
  3223.                 if(ScreenDepth < 2)
  3224.                     break;
  3225.                 else
  3226.                 {
  3227.                     ScreenDepth--;
  3228.  
  3229.                         /* Check to see whether we will be able to
  3230.                          * build a colour display or not.
  3231.                          */
  3232.  
  3233.                     while(cube_size >= 2)
  3234.                     {
  3235.                         if((max = cube_size * cube_size * cube_size) <= 1 << ScreenDepth)
  3236.                             break;
  3237.                         else
  3238.                             cube_size--;
  3239.                     }
  3240.  
  3241.                         /* Got enough colours? */
  3242.  
  3243.                     if(cube_size == 1 || ScreenDepth == 1)
  3244.                     {
  3245.                             /* Obviously not. */
  3246.  
  3247.                         ScreenDepth = 1;
  3248.  
  3249.                         set_mono_device((gx_device_amiga *)dev);
  3250.                     }
  3251.                 }
  3252.             }
  3253.         }
  3254.         while(!xdev -> screen);
  3255.  
  3256.             /* Did we succeed in opening the screen? */
  3257.  
  3258.         if(xdev -> screen)
  3259.         {
  3260.             if(xdev -> window = OpenWindowTags(NULL,
  3261.                 WA_Left,    0,
  3262.                 WA_Top,        0,
  3263.                 WA_Width,    xdev -> screen -> Width,
  3264.                 WA_Height,    xdev -> screen -> Height,
  3265.                 WA_Backdrop,    TRUE,
  3266.                 WA_RMBTrap,    TRUE,
  3267.                 WA_Borderless,    TRUE,
  3268.                 WA_CustomScreen,xdev -> screen,
  3269.             TAG_DONE))
  3270.             {
  3271.                 xdev -> rport    = xdev -> window -> RPort;
  3272.                 xdev -> width    = xdev -> screen -> Width;
  3273.                 xdev -> height    = xdev -> screen -> Height;
  3274.             }
  3275.             else
  3276.             {
  3277.                 xdev -> rport    = &xdev -> screen -> RastPort;
  3278.                 xdev -> width    = xdev -> screen -> Width;
  3279.                 xdev -> height    = xdev -> screen -> Height;
  3280.             }
  3281.  
  3282.                 /* Establish defaults. */
  3283.  
  3284.             DarkPen        = 0;
  3285.             LightPen    = 1;
  3286.  
  3287.             SetBPen(xdev -> rport,0);
  3288.             SetDrMd(xdev -> rport,JAM2);
  3289.  
  3290.                 /* Create the temporary drawing area. */
  3291.  
  3292.             if(xdev -> temp_rport = CreateTempRPort(xdev -> rport))
  3293.             {
  3294.                 if(xdev -> temp_array = (UBYTE *)AllocVec(xdev -> screen -> Width,MEMF_ANY))
  3295.                 {
  3296.                         /* Colour output enabled? */
  3297.  
  3298.                     if(xdev -> cube_size > 0)
  3299.                     {
  3300.                         LONG r,g,b,max = xdev -> cube_size - 1;
  3301.  
  3302.                         i = 0;
  3303.  
  3304.                             /* Build a suitable colour map. */
  3305.  
  3306.                         if(GfxBase -> LibNode . lib_Version >= 39)
  3307.                         {
  3308.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3309.                             {
  3310.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3311.                                 {
  3312.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3313.                                         SetRGB32(&xdev -> screen -> ViewPort,i++,SPREAD((255 * r) / max),SPREAD((255 * g) / max),SPREAD((255 * b) / max));
  3314.                                 }
  3315.                             }
  3316.                         }
  3317.                         else
  3318.                         {
  3319.                             for(r = 0 ; r < xdev -> cube_size ; r++)
  3320.                             {
  3321.                                 for(g = 0 ; g < xdev -> cube_size ; g++)
  3322.                                 {
  3323.                                     for(b = 0 ; b < xdev -> cube_size ; b++)
  3324.                                         SetRGB4(&xdev -> screen -> ViewPort,i++,(15 * r) / max,(15 * g) / max,(15 * b) / max);
  3325.                                 }
  3326.                             }
  3327.                         }
  3328.                     }
  3329.                 }
  3330.                 else
  3331.                 {
  3332.                     perror("Ghostscript: failed to allocate temporary line");
  3333.  
  3334.                     return(-1);
  3335.                 }
  3336.             }
  3337.             else
  3338.             {
  3339.                 perror("Ghostscript: failed to allocate temporary raster");
  3340.  
  3341.                 return(-1);
  3342.             }
  3343.  
  3344.             amiga_set_pen(dev,DarkPen);
  3345.  
  3346.             return(0);
  3347.         }
  3348.         else
  3349.             perror("Ghostscript: failed to open screen");
  3350.     }
  3351.     else
  3352.         perror("Ghostscript: failed to get display mode information");
  3353.  
  3354.     return(-1);
  3355. }
  3356.  
  3357.     /* amiga_output_page(gx_device *dev,int,int):
  3358.      *
  3359.      *    Page is not `buffered', just bring screen/window
  3360.      *    to the front.
  3361.      */
  3362.  
  3363. int
  3364. amiga_output_page(gx_device *dev,int num_copies,int flush)
  3365. {
  3366.     if(xdev -> screen)
  3367.         ScreenToFront(xdev -> screen);
  3368.     else
  3369.     {
  3370.         if(xdev -> window)
  3371.             WindowToFront(xdev -> window);
  3372.     }
  3373.  
  3374.     return(0);
  3375. }
  3376.  
  3377.     /* amiga_close(gx_device *dev):
  3378.      *
  3379.      *    Close the screen and free associated resources.
  3380.      */
  3381.  
  3382. int
  3383. amiga_close(gx_device *dev)
  3384. {
  3385.     if(xdev -> dispatcher)
  3386.     {
  3387.         const sigset_t trapped = sigmask(SIGINT);
  3388.  
  3389.         sigprocmask(SIG_BLOCK,&trapped,NULL);
  3390.  
  3391.         Forbid();
  3392.  
  3393.         Signal(xdev -> dispatcher,SIG_KILL);
  3394.  
  3395.         SetSignal(0,SIG_HANDSHAKE);
  3396.  
  3397.         Wait(SIG_HANDSHAKE);
  3398.  
  3399.         Permit();
  3400.  
  3401.         sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  3402.     }
  3403.  
  3404.     if(xdev -> temp_array)
  3405.     {
  3406.         FreeVec(xdev -> temp_array);
  3407.  
  3408.         xdev -> temp_array = NULL;
  3409.     }
  3410.  
  3411.     if(xdev -> pens)
  3412.     {
  3413.         LONG i;
  3414.  
  3415.         for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  3416.         {
  3417.             if(xdev -> pens[i] != -1)
  3418.                 ReleasePen(xdev -> window -> WScreen -> ViewPort . ColorMap,xdev -> pens[i]);
  3419.         }
  3420.  
  3421.         FreeVec(xdev -> pens);
  3422.  
  3423.         xdev -> pens = NULL;
  3424.     }
  3425.  
  3426.     if(xdev -> temp_rport)
  3427.     {
  3428.         DeleteTempRPort(xdev -> temp_rport);
  3429.  
  3430.         xdev -> temp_rport = NULL;
  3431.     }
  3432.  
  3433.     if(xdev -> window)
  3434.     {
  3435.         CloseWindow(xdev -> window);
  3436.  
  3437.         xdev -> window = NULL;
  3438.     }
  3439.  
  3440.     DeleteScrollers(dev);
  3441.  
  3442.     if(xdev -> super_bitmap)
  3443.     {
  3444.         DeleteBitMap(xdev -> super_bitmap,FALSE);
  3445.  
  3446.         xdev -> super_bitmap = NULL;
  3447.     }
  3448.  
  3449.     if(xdev -> screen)
  3450.     {
  3451.         CloseScreen(xdev -> screen);
  3452.  
  3453.         xdev -> screen = NULL;
  3454.     }
  3455.  
  3456.     xdev -> width = xdev -> height = 0;
  3457. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  3458.  
  3459.     return(0);
  3460. }
  3461.  
  3462.     /* amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color):
  3463.      *
  3464.      *    Fill a rectangle with a given colour. This one is simple as it can
  3465.      *    be done with the Amiga graphics primitives.
  3466.      */
  3467.  
  3468. int
  3469. amiga_fill_rectangle(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3470. {
  3471.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  3472.         return(-1);
  3473.     else
  3474.     {
  3475.         if(w > 0 && h > 0 && color != gx_no_color_index)
  3476.         {
  3477.             amiga_set_pen(dev,color);
  3478.  
  3479.             RectFill(xdev -> rport,x,y,x + w - 1,y + h - 1);
  3480.         }
  3481.  
  3482.         return(0);
  3483.     }
  3484. }
  3485.  
  3486.     /* amiga_copy_mono():
  3487.      *
  3488.      *    Copy a monochrome image. This operation requires a bit of work as
  3489.      *    we cannot simply blit the image into the bitmap.
  3490.      */
  3491.  
  3492. int
  3493. amiga_copy_mono(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3494. {
  3495.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3496.         return(-1);
  3497.     else
  3498.     {
  3499.         if(w > 0 && h > 0)
  3500.         {
  3501.             LONG i,j;
  3502.  
  3503.             if(zero == gx_no_color_index)
  3504.             {
  3505.                 if(one != gx_no_color_index)
  3506.                 {
  3507.                     do
  3508.                     {
  3509.                         ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3510.  
  3511.                         for(i = sourcex, j = 0 ; i < sourcex + w ; i++, j++)
  3512.                         {
  3513.                             if(base[i >> 3] & shift[i & 7])
  3514.                                 xdev -> temp_array[j] = one;
  3515.                         }
  3516.  
  3517.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3518.  
  3519.                         base += raster;
  3520.  
  3521.                         y++;
  3522.                     }
  3523.                     while(--h);
  3524.                 }
  3525.             }
  3526.             else
  3527.             {
  3528.                 if(one == gx_no_color_index)
  3529.                 {
  3530.                     do
  3531.                     {
  3532.                         ReadPixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3533.  
  3534.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3535.                         {
  3536.                             if(!(base[i >> 3] & shift[i & 7]))
  3537.                                 xdev -> temp_array[j] = zero;
  3538.                         }
  3539.  
  3540.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3541.  
  3542.                         base += raster;
  3543.  
  3544.                         y++;
  3545.                     }
  3546.                     while(--h);
  3547.                 }
  3548.                 else
  3549.                 {
  3550.                     do
  3551.                     {
  3552.                         for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3553.                         {
  3554.                             if(base[i >> 3] & shift[i & 7])
  3555.                                 xdev -> temp_array[j] = one;
  3556.                             else
  3557.                                 xdev -> temp_array[j] = zero;
  3558.                         }
  3559.  
  3560.                         WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3561.  
  3562.                         base += raster;
  3563.  
  3564.                         y++;
  3565.                     }
  3566.                     while(--h);
  3567.                 }
  3568.             }
  3569.         }
  3570.  
  3571.         return(0);
  3572.     }
  3573. }
  3574.  
  3575.     /* amiga_copy_color():
  3576.      *
  3577.      *    Copy a color image (oh well...). This is just the same as the
  3578.      *    copy_mono() routine.
  3579.      */
  3580.  
  3581. int
  3582. amiga_copy_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3583. {
  3584.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3585.         return(-1);
  3586.     else
  3587.     {
  3588.         if(w > 0 && h > 0)
  3589.         {
  3590.             LONG i,j;
  3591.  
  3592.             do
  3593.             {
  3594.                 for(i = sourcex, j = 0 ; i < w + sourcex ; i++, j++)
  3595.                 {
  3596.                     if(base[i >> 3] & shift[i & 7])
  3597.                         xdev -> temp_array[j] = DarkPen;
  3598.                     else
  3599.                         xdev -> temp_array[j] = LightPen;
  3600.                 }
  3601.  
  3602.                 WritePixelLine8(xdev -> rport,x,y,w,xdev -> temp_array,xdev -> temp_rport);
  3603.  
  3604.                 base += raster;
  3605.  
  3606.                 y++;
  3607.             }
  3608.             while(--h);
  3609.         }
  3610.  
  3611.         return(0);
  3612.     }
  3613. }
  3614.  
  3615.     /* amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color):
  3616.      *
  3617.      *    Draw a line between two points. This one is easy as it can be done
  3618.      *    with the Amiga graphics primitives, the only glitch is having to reset
  3619.      *    the last dot to its original colour.
  3620.      */
  3621.  
  3622. int
  3623. amiga_draw_line(gx_device *dev,int x0,int y0,int x1,int y1,gx_color_index color)
  3624. {
  3625.     if(color != gx_no_color_index && (x0 != x1 || y0 != y1))
  3626.     {
  3627.         LONG pen;
  3628.  
  3629.         pen = ReadPixel(xdev -> rport,x1,y1);
  3630.  
  3631.         amiga_set_pen(dev,color);
  3632.  
  3633.         Move(xdev -> rport,x0,y0);
  3634.         Draw(xdev -> rport,x1,y1);
  3635.  
  3636.         if(pen == color)
  3637.         {
  3638.             amiga_set_pen(dev,pen);
  3639.  
  3640.             WritePixel(xdev -> rport,x1,y1);
  3641.         }
  3642.     }
  3643.  
  3644.     return(0);
  3645. }
  3646.  
  3647.     /* amiga_copy_mono_raw():
  3648.      *
  3649.      *    Copy a monochrome image to a bitmap. Just watch the
  3650.      *    astounding number of case switches.
  3651.      */
  3652.  
  3653. int
  3654. amiga_copy_mono_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  3655. {
  3656.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3657.         return(-1);
  3658.     else
  3659.     {
  3660.         if(w > 0 && h > 0)
  3661.         {
  3662.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3663.             UBYTE *line;
  3664.  
  3665.             w += sourcex;
  3666.  
  3667.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3668.  
  3669.             if(zero == gx_no_color_index)
  3670.             {
  3671.                 if(one != gx_no_color_index)
  3672.                 {
  3673.                     if(one)
  3674.                     {
  3675.                         do
  3676.                         {
  3677.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3678.                             {
  3679.                                 if(base[i >> 3] & shift[i & 7])
  3680.                                     line[j >> 3] |= shift[j & 7];
  3681.                             }
  3682.  
  3683.                             base += raster;
  3684.  
  3685.                             line += modulo;
  3686.                         }
  3687.                         while(--h);
  3688.                     }
  3689.                     else
  3690.                     {
  3691.                         do
  3692.                         {
  3693.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3694.                             {
  3695.                                 if(base[i >> 3] & shift[i & 7])
  3696.                                     line[j >> 3] &= masks[j & 7];
  3697.                             }
  3698.  
  3699.                             base += raster;
  3700.  
  3701.                             line += modulo;
  3702.                         }
  3703.                         while(--h);
  3704.                     }
  3705.                 }
  3706.             }
  3707.             else
  3708.             {
  3709.                 if(one == gx_no_color_index)
  3710.                 {
  3711.                     if(zero)
  3712.                     {
  3713.                         do
  3714.                         {
  3715.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3716.                             {
  3717.                                 if(!(base[i >> 3] & shift[i & 7]))
  3718.                                     line[j >> 3] |= shift[j & 7];
  3719.                             }
  3720.  
  3721.                             base += raster;
  3722.  
  3723.                             line += modulo;
  3724.                         }
  3725.                         while(--h);
  3726.                     }
  3727.                     else
  3728.                     {
  3729.                         do
  3730.                         {
  3731.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3732.                             {
  3733.                                 if(!(base[i >> 3] & shift[i & 7]))
  3734.                                     line[j >> 3] &= masks[j & 7];
  3735.                             }
  3736.  
  3737.                             base += raster;
  3738.  
  3739.                             line += modulo;
  3740.                         }
  3741.                         while(--h);
  3742.                     }
  3743.                 }
  3744.                 else
  3745.                 {
  3746.                     if(one)
  3747.                     {
  3748.                         do
  3749.                         {
  3750.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3751.                             {
  3752.                                 if(base[i >> 3] & shift[i & 7])
  3753.                                     line[j >> 3] |= shift[j & 7];
  3754.                                 else
  3755.                                     line[j >> 3] &= masks[j & 7];
  3756.                             }
  3757.  
  3758.                             base += raster;
  3759.  
  3760.                             line += modulo;
  3761.                         }
  3762.                         while(--h);
  3763.                     }
  3764.                     else
  3765.                     {
  3766.                         do
  3767.                         {
  3768.                             for(i = sourcex, j = x ; i < w ; i++, j++)
  3769.                             {
  3770.                                 if(base[i >> 3] & shift[i & 7])
  3771.                                     line[j >> 3] &= masks[j & 7];
  3772.                                 else
  3773.                                     line[j >> 3] |= shift[j & 7];
  3774.                             }
  3775.  
  3776.                             base += raster;
  3777.  
  3778.                             line += modulo;
  3779.                         }
  3780.                         while(--h);
  3781.                     }
  3782.                 }
  3783.             }
  3784.         }
  3785.  
  3786.         return(0);
  3787.     }
  3788. }
  3789.  
  3790.     /* amiga_copy_color_raw():
  3791.      *
  3792.      *    Copy a color image (oh well...). This is just the same as the
  3793.      *    copy_mono() routine.
  3794.      */
  3795.  
  3796. int
  3797. amiga_copy_color_raw(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  3798. {
  3799.     if(y < 0 || x < 0 || w < 0 || h < 0)
  3800.         return(-1);
  3801.     else
  3802.     {
  3803.         if(w > 0 && h > 0)
  3804.         {
  3805.             LONG i,j,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3806.             UBYTE *line;
  3807.  
  3808.             line = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow;
  3809.  
  3810.             w += sourcex;
  3811.  
  3812.             do
  3813.             {
  3814.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  3815.                 {
  3816.                     if(base[i >> 3] & shift[i & 7])
  3817.                         line[j >> 3] |= shift[j & 7];
  3818.                     else
  3819.                         line[j >> 3] &= masks[j & 7];
  3820.                 }
  3821.  
  3822.                 base += raster;
  3823.  
  3824.                 line += modulo;
  3825.             }
  3826.             while(--h);
  3827.         }
  3828.  
  3829.         return(0);
  3830.     }
  3831. }
  3832.  
  3833.     /* amiga_fill_rectangle_raw():
  3834.      *
  3835.      *    Fill a rectangular area in a bitmap.
  3836.      */
  3837.  
  3838. int
  3839. amiga_fill_rectangle_raw(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  3840. {
  3841.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  3842.         return(-1);
  3843.     else
  3844.     {
  3845.         if(w > 0 && h > 0 && color != gx_no_color_index)
  3846.         {
  3847.             UBYTE *line,startmask,endmask;
  3848.             LONG right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow;
  3849.  
  3850.             right    = x + w;
  3851.             mid    = (right >> 3) - (x >> 3);
  3852.             line    = xdev -> rport -> BitMap -> Planes[0] + y * xdev -> rport -> BitMap -> BytesPerRow + (x >> 3);
  3853.  
  3854.             x    &= 7;
  3855.             right    &= 7;
  3856.  
  3857.             if(color)
  3858.             {
  3859.                 startmask    = 0xFF >> x;
  3860.                 endmask        = ~(0xFF >> right);
  3861.  
  3862.                 if(mid)
  3863.                 {
  3864.                     UBYTE *ptr;
  3865.                     int i;
  3866.  
  3867.                     do
  3868.                     {
  3869.                         ptr = line;
  3870.  
  3871.                         *ptr++ |= startmask;
  3872.  
  3873.                         i = mid;
  3874.  
  3875.                         while(--i > 0)
  3876.                             *ptr++ = 0xFF;
  3877.  
  3878.                         *ptr |= endmask;
  3879.  
  3880.                         line += modulo;
  3881.                     }
  3882.                     while(--h);
  3883.                 }
  3884.                 else
  3885.                 {
  3886.                     startmask &= endmask;
  3887.  
  3888.                     do
  3889.                     {
  3890.                         *line |= startmask;
  3891.  
  3892.                         line += modulo;
  3893.                     }
  3894.                     while(--h);
  3895.                 }
  3896.             }
  3897.             else
  3898.             {
  3899.                 startmask    = ~(0xFF >> x);
  3900.                 endmask        = 0xFF >> right;
  3901.  
  3902.                 if(mid)
  3903.                 {
  3904.                     UBYTE *ptr;
  3905.                     LONG i;
  3906.  
  3907.                     do
  3908.                     {
  3909.                         ptr = line;
  3910.  
  3911.                         *ptr++ &= startmask;
  3912.  
  3913.                         i = mid;
  3914.  
  3915.                         while(--i > 0)
  3916.                             *ptr++ = 0x00;
  3917.  
  3918.                         *ptr &= endmask;
  3919.  
  3920.                         line += modulo;
  3921.                     }
  3922.                     while(--h);
  3923.                 }
  3924.                 else
  3925.                 {
  3926.                     startmask |= endmask;
  3927.  
  3928.                     do
  3929.                     {
  3930.                         *line &= startmask;
  3931.  
  3932.                         line += modulo;
  3933.                     }
  3934.                     while(--h);
  3935.                 }
  3936.             }
  3937.         }
  3938.  
  3939.         return(0);
  3940.     }
  3941. }
  3942.  
  3943.     /* amiga_draw_line_raw():
  3944.      *
  3945.      *    Draw a hair line, your basic DDA algorithm;
  3946.      *    keep your fingers crossed.
  3947.      */
  3948.  
  3949. int
  3950. amiga_draw_line_raw(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  3951. {
  3952.     if(color != gx_no_color_index && (x != x1 || y != y1))
  3953.     {
  3954.         short xstep,ystep,dx,dy,diff,modulo;
  3955.         UBYTE *line,*plane,pen;
  3956.         LONG last;
  3957.  
  3958.         modulo    = xdev -> rport -> BitMap -> BytesPerRow;
  3959.         plane    = xdev -> rport -> BitMap -> Planes[0];
  3960.  
  3961.         line    = &plane[y1 * modulo];
  3962.         last    = y1;
  3963.         pen    = line[x1 >> 3] & (x1 & 7);
  3964.  
  3965.         dx = x1 - x;
  3966.         dy = y1 - y;
  3967.  
  3968.         if(dx < 0)
  3969.         {
  3970.             dx = -dx;
  3971.             dy = -dy;
  3972.  
  3973.             x = x1;
  3974.             y = y1;
  3975.         }
  3976.  
  3977.         if(y != last)
  3978.             line = &plane[(last = y) * modulo];
  3979.  
  3980.         if(color)
  3981.         {
  3982.             line[x >> 3] |= shift[x & 7];
  3983.  
  3984.             xstep = ystep = 0;
  3985.  
  3986.             if(dy < 0)
  3987.             {
  3988.                 if(dx > -dy)
  3989.                 {
  3990.                     diff = -dx / 2;
  3991.  
  3992.                     do
  3993.                     {
  3994.                         xstep++;
  3995.  
  3996.                         if(diff > 0)
  3997.                         {
  3998.                             ystep--;
  3999.  
  4000.                             diff = diff - dy - dx;
  4001.                         }
  4002.                         else
  4003.                             diff -= dy;
  4004.  
  4005.                         {
  4006.                             LONG x1 = x + xstep,y1 = y + ystep;
  4007.  
  4008.                             if(y1 != last)
  4009.                                 line = &plane[(last = y1) * modulo];
  4010.  
  4011.                             line[x1 >> 3] |= shift[x1 & 7];
  4012.                         }
  4013.                     }
  4014.                     while(xstep < dx);
  4015.                 }
  4016.                 else
  4017.                 {
  4018.                     if(dx == -dy)
  4019.                         diff = 0;
  4020.                     else
  4021.                         diff = -dy / 2;
  4022.  
  4023.                     do
  4024.                     {
  4025.                         ystep--;
  4026.  
  4027.                         if(diff > 0)
  4028.                             diff -= dx;
  4029.                         else
  4030.                         {
  4031.                             xstep++;
  4032.  
  4033.                             diff = diff - dy - dx;
  4034.                         }
  4035.  
  4036.                         {
  4037.                             LONG x1 = x + xstep,y1 = y + ystep;
  4038.  
  4039.                             if(y1 != last)
  4040.                                 line = &plane[(last = y1) * modulo];
  4041.  
  4042.                             line[x1 >> 3] |= shift[x1 & 7];
  4043.                         }
  4044.                     }
  4045.                     while(ystep > dy);
  4046.                 }
  4047.             }
  4048.             else
  4049.             {
  4050.                 if(dx > dy)
  4051.                 {
  4052.                     diff = -dx / 2;
  4053.  
  4054.                     do
  4055.                     {
  4056.                         xstep++;
  4057.  
  4058.                         if(diff > 0)
  4059.                         {
  4060.                             ystep++;
  4061.  
  4062.                             diff = diff + dy - dx;
  4063.                         }
  4064.                         else
  4065.                             diff += dy;
  4066.  
  4067.                         {
  4068.                             LONG x1 = x + xstep,y1 = y + ystep;
  4069.  
  4070.                             if(y1 != last)
  4071.                                 line = &plane[(last = y1) * modulo];
  4072.  
  4073.                             line[x1 >> 3] |= shift[x1 & 7];
  4074.                         }
  4075.                     }
  4076.                     while(xstep < dx);
  4077.                 }
  4078.                 else
  4079.                 {
  4080.                     if(dx == dy)
  4081.                         diff = 0;
  4082.                     else
  4083.                         diff = dy / 2;
  4084.  
  4085.                     do
  4086.                     {
  4087.                         ystep++;
  4088.  
  4089.                         if(diff > 0)
  4090.                             diff -= dx;
  4091.                         else
  4092.                         {
  4093.                             xstep++;
  4094.  
  4095.                             diff = diff + dy - dx;
  4096.                         }
  4097.  
  4098.                         {
  4099.                             LONG x1 = x + xstep,y1 = y + ystep;
  4100.  
  4101.                             if(y1 != last)
  4102.                                 line = &plane[(last = y1) * modulo];
  4103.  
  4104.                             line[x1 >> 3] |= shift[x1 & 7];
  4105.                         }
  4106.                     }
  4107.                     while(ystep < dy);
  4108.                 }
  4109.             }
  4110.  
  4111.             if(!pen)
  4112.             {
  4113.                 if(y1 != last)
  4114.                     line = &plane[(last = y1) * modulo];
  4115.  
  4116.                 line[x1 >> 3] &= masks[x1 & 7];
  4117.             }
  4118.         }
  4119.         else
  4120.         {
  4121.             line[x >> 3] &= masks[x & 7];
  4122.  
  4123.             xstep = ystep = 0;
  4124.  
  4125.             if(dy < 0)
  4126.             {
  4127.                 if(dx > -dy)
  4128.                 {
  4129.                     diff = -dx / 2;
  4130.  
  4131.                     do
  4132.                     {
  4133.                         xstep++;
  4134.  
  4135.                         if(diff > 0)
  4136.                         {
  4137.                             ystep--;
  4138.  
  4139.                             diff = diff - dy - dx;
  4140.                         }
  4141.                         else
  4142.                             diff -= dy;
  4143.  
  4144.                         {
  4145.                             LONG x1 = x + xstep,y1 = y + ystep;
  4146.  
  4147.                             if(y1 != last)
  4148.                                 line = &plane[(last = y1) * modulo];
  4149.  
  4150.                             line[x1 >> 3] &= masks[x1 & 7];
  4151.                         }
  4152.                     }
  4153.                     while(xstep < dx);
  4154.                 }
  4155.                 else
  4156.                 {
  4157.                     if(dx == -dy)
  4158.                         diff = 0;
  4159.                     else
  4160.                         diff = -dy / 2;
  4161.  
  4162.                     do
  4163.                     {
  4164.                         ystep--;
  4165.  
  4166.                         if(diff > 0)
  4167.                             diff -= dx;
  4168.                         else
  4169.                         {
  4170.                             xstep++;
  4171.  
  4172.                             diff = diff - dy - dx;
  4173.                         }
  4174.  
  4175.                         {
  4176.                             LONG x1 = x + xstep,y1 = y + ystep;
  4177.  
  4178.                             if(y1 != last)
  4179.                                 line = &plane[(last = y1) * modulo];
  4180.  
  4181.                             line[x1 >> 3] &= masks[x1 & 7];
  4182.                         }
  4183.                     }
  4184.                     while(ystep > dy);
  4185.                 }
  4186.             }
  4187.             else
  4188.             {
  4189.                 if(dx > dy)
  4190.                 {
  4191.                     diff = -dx / 2;
  4192.  
  4193.                     do
  4194.                     {
  4195.                         xstep++;
  4196.  
  4197.                         if(diff > 0)
  4198.                         {
  4199.                             ystep++;
  4200.  
  4201.                             diff = diff + dy - dx;
  4202.                         }
  4203.                         else
  4204.                             diff += dy;
  4205.  
  4206.                         {
  4207.                             LONG x1 = x + xstep,y1 = y + ystep;
  4208.  
  4209.                             if(y1 != last)
  4210.                                 line = &plane[(last = y1) * modulo];
  4211.  
  4212.                             line[x1 >> 3] &= masks[x1 & 7];
  4213.                         }
  4214.                     }
  4215.                     while(xstep < dx);
  4216.                 }
  4217.                 else
  4218.                 {
  4219.                     if(dx == dy)
  4220.                         diff = 0;
  4221.                     else
  4222.                         diff =  dy / 2;
  4223.  
  4224.                     do
  4225.                     {
  4226.                         ystep++;
  4227.  
  4228.                         if(diff > 0)
  4229.                             diff -= dx;
  4230.                         else
  4231.                         {
  4232.                             xstep++;
  4233.  
  4234.                             diff = diff + dy - dx;
  4235.                         }
  4236.  
  4237.                         {
  4238.                             LONG x1 = x + xstep,y1 = y + ystep;
  4239.  
  4240.                             if(y1 != last)
  4241.                                 line = &plane[(last = y1) * modulo];
  4242.  
  4243.                             line[x1 >> 3] &= masks[x1 & 7];
  4244.                         }
  4245.                     }
  4246.                     while(ystep < dy);
  4247.                 }
  4248.             }
  4249.  
  4250.             if(pen)
  4251.             {
  4252.                 if(y1 != last)
  4253.                     line = &plane[(last = y1) * modulo];
  4254.  
  4255.                 line[x1 >> 3] |= pen;
  4256.             }
  4257.         }
  4258.     }
  4259.  
  4260.     return(0);
  4261. }
  4262.  
  4263.     /* amiga_open_ilbm(gx_device *dev):
  4264.      *
  4265.      *    Open the ilbm device.
  4266.      */
  4267.  
  4268. int
  4269. amiga_open_ilbm(gx_device *dev)
  4270. {
  4271.     if(xdev -> width <= 0 || xdev -> height <= 0)
  4272.     {
  4273.         if(xdev -> page_width > 0.0)
  4274.             xdev -> width = (int)(xdev -> x_pixels_per_inch * xdev -> page_width);
  4275.         else
  4276.             xdev -> width = 640;
  4277.  
  4278.         if(xdev -> page_height > 0.0)
  4279.             xdev -> height = (int)(xdev -> y_pixels_per_inch * xdev -> page_height);
  4280.         else
  4281.             xdev -> height = 512;
  4282.     }
  4283.  
  4284.     if(xdev -> rport = (struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_ANY))
  4285.     {
  4286.         InitRastPort(xdev -> rport);
  4287.  
  4288.         if(xdev -> bitmap = (struct BitMap *)AllocVec(sizeof(struct BitMap),MEMF_ANY))
  4289.         {
  4290.             InitBitMap(xdev -> bitmap,1,xdev -> width,xdev -> height);
  4291.  
  4292.             if(xdev -> bitplane = AllocVec(xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,MEMF_ANY | MEMF_CLEAR))
  4293.             {
  4294.                 xdev -> bitmap -> Planes[0]    = xdev -> bitplane;
  4295.                 xdev -> rport -> BitMap        = xdev -> bitmap;
  4296.                 xdev -> page_count        = 1;
  4297.  
  4298.                 DarkPen        = 0;
  4299.                 LightPen    = 1;
  4300.  
  4301.                 return(0);
  4302.             }
  4303.             else
  4304.             {
  4305.                 char buffer[256];
  4306.  
  4307.                 sprintf(buffer,"Ghostscript: failed to allocate raster (wanted %ld, largest %ld)",xdev -> bitmap -> Rows * xdev -> bitmap -> BytesPerRow,AvailMem(MEMF_ANY | MEMF_LARGEST));
  4308.  
  4309.                 perror(buffer);
  4310.             }
  4311.         }
  4312.         else
  4313.             perror("Ghostscript: failed to allocate bitmap");
  4314.     }
  4315.     else
  4316.         perror("Ghostscript: failed to allocate raster port");
  4317.  
  4318.     return(-1);
  4319. }
  4320.  
  4321.     /* amiga_output_page_ilbm(gx_device *dev,int,int):
  4322.      *
  4323.      *    Send a bitmap to an IFF-ILBM file.
  4324.      */
  4325.  
  4326. int
  4327. amiga_output_page_ilbm(gx_device *dev,int num_copies,int flush)
  4328. {
  4329.     const sigset_t trapped = sigmask(SIGINT);
  4330.     char buffer[270];
  4331.     LONG result = -1;
  4332.  
  4333.     sprintf(buffer,"%s_%04d.ilbm",xdev -> file_name,xdev -> page_count);
  4334.  
  4335.     fprintf(stdout,"\n\033[ASaving page Nº%d to \"%s\"...\033[K",xdev -> page_count,buffer);
  4336.     fflush(stdout);
  4337.  
  4338.     sigprocmask(SIG_BLOCK,&trapped,NULL);
  4339.  
  4340.     if(SaveBitMap(buffer,xdev -> bitmap,xdev -> width,xdev -> height,(UWORD)xdev -> x_pixels_per_inch,xdev -> y_pixels_per_inch))
  4341.     {
  4342.         fprintf(stdout,"\n\033[APage saved to file \"%s\".\033[K\n",buffer);
  4343.  
  4344.         result = 0;
  4345.  
  4346.         xdev -> page_count;
  4347.     }
  4348.     else
  4349.         perror("\n\033[AGhostscript: error saving page\033[K");
  4350.  
  4351.     sigprocmask(SIG_UNBLOCK,&trapped,NULL);
  4352.  
  4353.     return(result);
  4354. }
  4355.  
  4356.     /* amiga_close_ilbm(gx_device *dev):
  4357.      *
  4358.      *    Close the ilbm driver.
  4359.      */
  4360.  
  4361. int
  4362. amiga_close_ilbm(gx_device *dev)
  4363. {
  4364.     if(xdev -> bitplane)
  4365.     {
  4366.         FreeVec(xdev -> bitplane);
  4367.  
  4368.         xdev -> bitplane = NULL;
  4369.     }
  4370.  
  4371.     if(xdev -> bitmap)
  4372.     {
  4373.         FreeVec(xdev -> bitmap);
  4374.  
  4375.         xdev -> bitmap = NULL;
  4376.     }
  4377.  
  4378.     if(xdev -> rport)
  4379.     {
  4380.         FreeVec(xdev -> rport);
  4381.  
  4382.         xdev -> rport = NULL;
  4383.     }
  4384.  
  4385.     xdev -> width = xdev -> height = 0;
  4386. /*    xdev -> x_pixels_per_inch = x_pixels_per_inch = 72.72;*/
  4387.  
  4388.     return(0);
  4389. }
  4390.  
  4391. private const gs_prop_item props_amiga[] =
  4392. {
  4393.     prop_def("PageWidth",    prt_string),
  4394.     prop_def("PageHeight",    prt_string),
  4395.     prop_def("OutputFile",    prt_string)
  4396. };
  4397.  
  4398. int
  4399. amiga_get_props(gx_device *dev,gs_prop_item *plist)
  4400. {
  4401.     int start = gx_default_get_props(dev,plist);
  4402.  
  4403.     if(plist != 0)
  4404.     {
  4405.         gs_prop_item *pi = plist + start;
  4406.  
  4407.         memcpy(pi,props_amiga,sizeof(props_amiga));
  4408.  
  4409.         pi[0] . value .a.p.s    = "";
  4410.         pi[0] . value .a.size    = -1;
  4411.  
  4412.         pi[1] . value .a.p.s    = "";
  4413.         pi[1] . value .a.size    = -1;
  4414.  
  4415.         pi[2] . value .a.p.s    = "";
  4416.         pi[2] . value .a.size    = -1;
  4417.     }
  4418.  
  4419.     return(start + (sizeof(props_amiga) / sizeof(gs_prop_item)));
  4420. }
  4421.  
  4422. int
  4423. amiga_put_props(gx_device *dev,gs_prop_item *plist,int count)
  4424. {
  4425.     gs_prop_item *known[3];
  4426.     LONG code = 0;
  4427.  
  4428.     props_extract(plist,count,props_amiga,3,known,0);
  4429.  
  4430.     if((code = gx_default_put_props(dev,plist,count)) < 0)
  4431.         return(code);
  4432.     else
  4433.     {
  4434.         if(known[0] != 0)
  4435.         {
  4436.             gs_prop_item *pn = known[0];
  4437.             LONG size = pn -> value . a . size;
  4438.             char temp[256];
  4439.  
  4440.             if(size >= 256)
  4441.             {
  4442.                 pn -> status = pv_limitcheck;
  4443.  
  4444.                 code = gs_error_limitcheck;
  4445.             }
  4446.             else
  4447.             {
  4448.                 memcpy(temp,pn -> value . a . p . s,size);
  4449.  
  4450.                 temp[size] = 0;
  4451.  
  4452.                 xdev -> page_width = GetInches(temp);
  4453.  
  4454.                 if(xdev -> page_width <= 0.0)
  4455.                 {
  4456.                     xdev -> page_width = 0.0;
  4457.  
  4458.                     pn -> status = pv_limitcheck;
  4459.  
  4460.                     code = gs_error_limitcheck;
  4461.                 }
  4462.                 else
  4463.                 {
  4464.                     if(code == 0)
  4465.                         code = 1;
  4466.                 }
  4467.             }
  4468.         }
  4469.  
  4470.         if(known[1] != 0)
  4471.         {
  4472.             gs_prop_item *pn = known[1];
  4473.             LONG size = pn -> value . a . size;
  4474.             char temp[256];
  4475.  
  4476.             if(size >= 256)
  4477.             {
  4478.                 pn -> status = pv_limitcheck;
  4479.  
  4480.                 code = gs_error_limitcheck;
  4481.             }
  4482.             else
  4483.             {
  4484.                 memcpy(temp,pn -> value . a . p . s,size);
  4485.  
  4486.                 temp[size] = 0;
  4487.  
  4488.                 xdev -> page_height = GetInches(temp);
  4489.  
  4490.                 if(xdev -> page_height <= 0.0)
  4491.                 {
  4492.                     xdev -> page_height = 0.0;
  4493.  
  4494.                     pn -> status = pv_limitcheck;
  4495.  
  4496.                     code = gs_error_limitcheck;
  4497.                 }
  4498.                 else
  4499.                 {
  4500.                     if(code == 0)
  4501.                         code = 1;
  4502.                 }
  4503.             }
  4504.         }
  4505.  
  4506.         if(known[2] != 0)
  4507.         {
  4508.             gs_prop_item *pn = known[2];
  4509.             LONG size = pn -> value . a . size;
  4510.  
  4511.             if(size >= 256)
  4512.             {
  4513.                 pn -> status = pv_limitcheck;
  4514.  
  4515.                 code = gs_error_limitcheck;
  4516.             }
  4517.             else
  4518.             {
  4519.                 memcpy(xdev -> file_name,pn -> value . a . p . s,size);
  4520.  
  4521.                 xdev -> file_name[size] = 0;
  4522.             }
  4523.         }
  4524.  
  4525.         if(code < 0)
  4526.             return_error(code);
  4527.  
  4528.         if(xdev -> is_open && code)
  4529.         {
  4530.             LONG ccode = gs_closedevice(dev);
  4531.  
  4532.             if(ccode < 0)
  4533.                 return(ccode);
  4534.         }
  4535.  
  4536.         return(code);
  4537.     }
  4538. }
  4539.  
  4540.     /* amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4541.      *
  4542.      *    Turn an RGB colour into a pen index.
  4543.      */
  4544.  
  4545. gx_color_index
  4546. amiga_color_map_rgb_color(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4547. {
  4548.     LONG max = xdev -> cube_size - 1,r,g,b;
  4549.  
  4550.     r = (max * red)   / gx_max_color_value;
  4551.     g = (max * green) / gx_max_color_value;
  4552.     b = (max * blue)  / gx_max_color_value;
  4553.  
  4554.     return((r * xdev -> cube_size + g) * xdev -> cube_size + b);
  4555. }
  4556.  
  4557.     /* amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4558.      *
  4559.      *    Turn a pen index into RGB colour values.
  4560.      */
  4561.  
  4562. int
  4563. amiga_color_map_color_rgb(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4564. {
  4565.     LONG i,value,max = xdev -> cube_size - 1;
  4566.  
  4567.     for(i = 2 ; i >= 0 ; i--)
  4568.     {
  4569.         value = color % xdev -> cube_size;
  4570.  
  4571.         rgb[i] = (gx_max_color_value * value) / max;
  4572.  
  4573.         color /= xdev -> cube_size;
  4574.     }
  4575.  
  4576.     return(0);
  4577. }
  4578.  
  4579.     /* amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue):
  4580.      *
  4581.      *    Turn an RGB colour into a pen index; this routine takes remapped
  4582.      *    pens into account.
  4583.      */
  4584.  
  4585. gx_color_index
  4586. amiga_color_map_rgb_color_pen(gx_device *dev,gx_color_value red,gx_color_value green,gx_color_value blue)
  4587. {
  4588.     LONG max = xdev -> cube_size - 1,r,g,b;
  4589.  
  4590.     r = (max * red)   / gx_max_color_value;
  4591.     g = (max * green) / gx_max_color_value;
  4592.     b = (max * blue)  / gx_max_color_value;
  4593.  
  4594.     return(xdev -> pens[(r * xdev -> cube_size + g) * xdev -> cube_size + b]);
  4595. }
  4596.  
  4597.     /* amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3]):
  4598.      *
  4599.      *    Turn a pen index into RGB colour values; this routine takes remapped
  4600.      *    pens into account.
  4601.      */
  4602.  
  4603. int
  4604. amiga_color_map_color_rgb_pen(gx_device *dev,gx_color_index color,gx_color_value rgb[3])
  4605. {
  4606.     LONG i,value,max = xdev -> cube_size - 1;
  4607.  
  4608.         /* Find the matching pen... */
  4609.  
  4610.     for(i = 0 ; i < xdev -> cube_size * xdev -> cube_size * xdev -> cube_size ; i++)
  4611.     {
  4612.         if(xdev -> pens[i] == color)
  4613.         {
  4614.             color = i;
  4615.  
  4616.             break;
  4617.         }
  4618.     }
  4619.  
  4620.     for(i = 2 ; i >= 0 ; i--)
  4621.     {
  4622.         value = color % xdev -> cube_size;
  4623.  
  4624.         rgb[i] = (gx_max_color_value * value) / max;
  4625.  
  4626.         color /= xdev -> cube_size;
  4627.     }
  4628.  
  4629.     return(0);
  4630. }
  4631.  
  4632.     /* amiga_copy_color8():
  4633.      *
  4634.      *    Copy a color image, the source is guaranteed to consist of
  4635.      *    one byte per colour.
  4636.      */
  4637.  
  4638. int
  4639. amiga_copy_color8(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4640. {
  4641.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4642.         return(-1);
  4643.     else
  4644.     {
  4645.         if(w > 0 && h > 0)
  4646.         {
  4647.             base += sourcex;
  4648.  
  4649.             do
  4650.             {
  4651.                 WritePixelLine8(xdev -> rport,x,y++,w,(UBYTE *)base,xdev -> temp_rport);
  4652.  
  4653.                 base += raster;
  4654.             }
  4655.             while(--h);
  4656.         }
  4657.  
  4658.         return(0);
  4659.     }
  4660. }
  4661.  
  4662.     /* amiga_copy_mono_raw_color():
  4663.      *
  4664.      *    Copy a monochrome image to a bitmap.
  4665.      */
  4666.  
  4667. int
  4668. amiga_copy_mono_raw_color(gx_device *dev,const UBYTE *base,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h,gx_color_index zero,gx_color_index one)
  4669. {
  4670.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4671.         return(-1);
  4672.     else
  4673.     {
  4674.         if(w > 0 && h > 0 && zero != gx_no_color_index && one != gx_no_color_index)
  4675.         {
  4676.             PLANEPTR line[12];
  4677.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4678.  
  4679.             for(i = 0 ; i < depth ; i++)
  4680.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4681.  
  4682.             w += sourcex;
  4683.  
  4684.             if(zero == gx_no_color_index)
  4685.             {
  4686.                 do
  4687.                 {
  4688.                     for(i = sourcex, j = x ; i < w ; i++, j++)
  4689.                     {
  4690.                         if(base[i >> 3] & shift[i & 7])
  4691.                         {
  4692.                             for(k = 0 ; k < depth ; k++)
  4693.                             {
  4694.                                 if(one & (1 << k))
  4695.                                     line[k][j >> 3] |= shift[j & 7];
  4696.                                 else
  4697.                                     line[k][j >> 3] &= masks[j & 7];
  4698.                             }
  4699.                         }
  4700.                     }
  4701.  
  4702.                     base += raster;
  4703.  
  4704.                     for(k = 0 ; k < depth ; k++)
  4705.                         line[k] += modulo;
  4706.                 }
  4707.                 while(--h);
  4708.             }
  4709.             else
  4710.             {
  4711.                 if(one == gx_no_color_index)
  4712.                 {
  4713.                     do
  4714.                     {
  4715.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  4716.                         {
  4717.                             if(base[i >> 3] & shift[i & 7])
  4718.                             {
  4719.                                 for(k = 0 ; k < depth ; k++)
  4720.                                 {
  4721.                                     if(zero & (1 << k))
  4722.                                         line[k][j >> 3] |= shift[j & 7];
  4723.                                     else
  4724.                                         line[k][j >> 3] &= masks[j & 7];
  4725.                                 }
  4726.                             }
  4727.                         }
  4728.  
  4729.                         base += raster;
  4730.  
  4731.                         for(k = 0 ; k < depth ; k++)
  4732.                             line[k] += modulo;
  4733.                     }
  4734.                     while(--h);
  4735.                 }
  4736.                 else
  4737.                 {
  4738.                     do
  4739.                     {
  4740.                         for(i = sourcex, j = x ; i < w ; i++, j++)
  4741.                         {
  4742.                             if(base[i >> 3] & shift[i & 7])
  4743.                             {
  4744.                                 for(k = 0 ; k < depth ; k++)
  4745.                                 {
  4746.                                     if(one & (1 << k))
  4747.                                         line[k][j >> 3] |= shift[j & 7];
  4748.                                     else
  4749.                                         line[k][j >> 3] &= masks[j & 7];
  4750.                                 }
  4751.                             }
  4752.                             else
  4753.                             {
  4754.                                 for(k = 0 ; k < depth ; k++)
  4755.                                 {
  4756.                                     if(zero & (1 << k))
  4757.                                         line[k][j >> 3] |= shift[j & 7];
  4758.                                     else
  4759.                                         line[k][j >> 3] &= masks[j & 7];
  4760.                                 }
  4761.                             }
  4762.                         }
  4763.  
  4764.                         base += raster;
  4765.  
  4766.                         for(k = 0 ; k < depth ; k++)
  4767.                             line[k] += modulo;
  4768.                     }
  4769.                     while(--h);
  4770.                 }
  4771.             }
  4772.         }
  4773.  
  4774.         return(0);
  4775.     }
  4776. }
  4777.  
  4778.     /* amiga_copy_color_raw_color16():
  4779.      *
  4780.      *    Copy a color image, the source data is guaranteed to consist
  4781.      *    of one word per colour.
  4782.      */
  4783.  
  4784. int
  4785. amiga_copy_color_raw_color16(gx_device *dev,const UBYTE *data,int sourcex,int raster,gx_bitmap_id id,int x,int y,int w,int h)
  4786. {
  4787.     if(y < 0 || x < 0 || w < 0 || h < 0)
  4788.         return(-1);
  4789.     else
  4790.     {
  4791.         if(w > 0 && h > 0)
  4792.         {
  4793.             PLANEPTR line[12];
  4794.             LONG i,j,k,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4795.             UWORD *base = (UWORD *)data;
  4796.  
  4797.             for(i = 0 ; i < depth ; i++)
  4798.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo;
  4799.  
  4800.             w += sourcex;
  4801.  
  4802.             raster /= 2;
  4803.  
  4804.             do
  4805.             {
  4806.                 for(i = sourcex, j = x ; i < w ; i++, j++)
  4807.                 {
  4808.                     for(k = 0 ; k < depth ; k++)
  4809.                     {
  4810.                         if(base[i] & (1 << k))
  4811.                             line[k][j >> 3] |= shift[j & 7];
  4812.                         else
  4813.                             line[k][j >> 3] &= masks[j & 7];
  4814.                     }
  4815.                 }
  4816.  
  4817.                 base += raster;
  4818.  
  4819.                 for(k = 0 ; k < depth ; k++)
  4820.                     line[k] += modulo;
  4821.             }
  4822.             while(--h);
  4823.         }
  4824.  
  4825.         return(0);
  4826.     }
  4827. }
  4828.  
  4829.     /* amiga_fill_rectangle_raw_color():
  4830.      *
  4831.      *    Fill a rectangular area in a bitmap.
  4832.      */
  4833.  
  4834. int
  4835. amiga_fill_rectangle_raw_color(gx_device *dev,int x,int y,int w,int h,gx_color_index color)
  4836. {
  4837.     if(x < 0 || x > xdev -> width - w || y < 0 || y > xdev -> height - h)
  4838.         return(-1);
  4839.     else
  4840.     {
  4841.         if(w > 0 && h > 0 && color != gx_no_color_index)
  4842.         {
  4843.             PLANEPTR line[12];
  4844.             LONG i,j,right,mid,modulo = xdev -> rport -> BitMap -> BytesPerRow,depth = xdev -> rport -> BitMap -> Depth;
  4845.  
  4846.             for(i = 0 ; i < depth ; i++)
  4847.                 line[i] = xdev -> rport -> BitMap -> Planes[i] + y * modulo + (x >> 3);
  4848.  
  4849.             right    = x + w;
  4850.             mid    = (right >> 3) - (x >> 3);
  4851.  
  4852.             x    &= 7;
  4853.             right    &= 7;
  4854.  
  4855.             if(mid)
  4856.             {
  4857.                 UBYTE *ptr;
  4858.  
  4859.                 do
  4860.                 {
  4861.                     for(j = 0 ; j < depth ; j++)
  4862.                     {
  4863.                         ptr = line[j];
  4864.  
  4865.                         i = mid;
  4866.  
  4867.                         if(color & (1 << j))
  4868.                         {
  4869.                             *ptr++ |= 0xFF >> x;
  4870.  
  4871.                             while(--i > 0)
  4872.                                 *ptr++ = 0xFF;
  4873.  
  4874.                             *ptr |= ~(0xFF >> right);
  4875.                         }
  4876.                         else
  4877.                         {
  4878.                             *ptr++ &= ~(0xFF >> x);
  4879.  
  4880.                             while(--i > 0)
  4881.                                 *ptr++ = 0x00;
  4882.  
  4883.                             *ptr &= 0xFF >> right;
  4884.                         }
  4885.  
  4886.                         line[j] += modulo;
  4887.                     }
  4888.                 }
  4889.                 while(--h);
  4890.             }
  4891.             else
  4892.             {
  4893.                 UBYTE    one_mask    = (0xFF >> x) & ~(0xFF >> right),
  4894.                     zero_mask    = ~(0xFF >> x) | (0xFF >> right);
  4895.                 do
  4896.                 {
  4897.                     for(j = 0 ; j < depth ; j++)
  4898.                     {
  4899.                         if(color & (1 << j))
  4900.                             *line[j] |= one_mask;
  4901.                         else
  4902.                             *line[j] &= zero_mask;
  4903.  
  4904.                         line[j] += modulo;
  4905.                     }
  4906.                 }
  4907.                 while(--h);
  4908.             }
  4909.         }
  4910.  
  4911.         return(0);
  4912.     }
  4913. }
  4914.  
  4915.     /* amiga_draw_line_raw_color():
  4916.      *
  4917.      *    Draw a hair line, your basic DDA algorithm;
  4918.      *    keep your fingers crossed.
  4919.      */
  4920.  
  4921. int
  4922. amiga_draw_line_raw_color(gx_device *dev,int x,int y,int x1,int y1,gx_color_index color)
  4923. {
  4924.     if(color != gx_no_color_index && (x != x1 || y != y1))
  4925.     {
  4926.         LONG xstep,ystep,dx,dy,diff,modulo;
  4927.         UBYTE *line,*plane,pen;
  4928.         LONG last,i,orig_x = x,orig_y = y;
  4929.  
  4930.         modulo = xdev -> rport -> BitMap -> BytesPerRow;
  4931.  
  4932.         for(i = 0 ; i < xdev -> rport -> BitMap -> Depth ; i++)
  4933.         {
  4934.             plane    = xdev -> rport -> BitMap -> Planes[i];
  4935.             line    = &plane[y1 * modulo];
  4936.             last    = y1;
  4937.             pen    = line[x1 >> 3] & (x1 & 7);
  4938.             x    = orig_x;
  4939.             y    = orig_y;
  4940.  
  4941.             dx = x1 - x;
  4942.             dy = y1 - y;
  4943.  
  4944.             if(dx < 0)
  4945.             {
  4946.                 dx = -dx;
  4947.                 dy = -dy;
  4948.  
  4949.                 x = x1;
  4950.                 y = y1;
  4951.             }
  4952.  
  4953.             if(y != last)
  4954.                 line = &plane[(last = y) * modulo];
  4955.  
  4956.             if(color & (1 << i))
  4957.             {
  4958.                 line[x >> 3] |= shift[x & 7];
  4959.  
  4960.                 xstep = ystep = 0;
  4961.  
  4962.                 if(dy < 0)
  4963.                 {
  4964.                     if(dx > -dy)
  4965.                     {
  4966.                         diff = -dx / 2;
  4967.  
  4968.                         do
  4969.                         {
  4970.                             xstep++;
  4971.  
  4972.                             if(diff > 0)
  4973.                             {
  4974.                                 ystep--;
  4975.  
  4976.                                 diff = diff - dy - dx;
  4977.                             }
  4978.                             else
  4979.                                 diff -= dy;
  4980.  
  4981.                             {
  4982.                                 LONG x1 = x + xstep,y1 = y + ystep;
  4983.  
  4984.                                 if(y1 != last)
  4985.                                     line = &plane[(last = y1) * modulo];
  4986.  
  4987.                                 line[x1 >> 3] |= shift[x1 & 7];
  4988.                             }
  4989.                         }
  4990.                         while(xstep < dx);
  4991.                     }
  4992.                     else
  4993.                     {
  4994.                         if(dx == -dy)
  4995.                             diff = 0;
  4996.                         else
  4997.                             diff = -dy / 2;
  4998.  
  4999.                         do
  5000.                         {
  5001.                             ystep--;
  5002.  
  5003.                             if(diff > 0)
  5004.                                 diff -= dx;
  5005.                             else
  5006.                             {
  5007.                                 xstep++;
  5008.  
  5009.                                 diff = diff - dy - dx;
  5010.                             }
  5011.  
  5012.                             {
  5013.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5014.  
  5015.                                 if(y1 != last)
  5016.                                     line = &plane[(last = y1) * modulo];
  5017.  
  5018.                                 line[x1 >> 3] |= shift[x1 & 7];
  5019.                             }
  5020.                         }
  5021.                         while(ystep > dy);
  5022.                     }
  5023.                 }
  5024.                 else
  5025.                 {
  5026.                     if(dx > dy)
  5027.                     {
  5028.                         diff = -dx / 2;
  5029.  
  5030.                         do
  5031.                         {
  5032.                             xstep++;
  5033.  
  5034.                             if(diff > 0)
  5035.                             {
  5036.                                 ystep++;
  5037.  
  5038.                                 diff = diff + dy - dx;
  5039.                             }
  5040.                             else
  5041.                                 diff += dy;
  5042.  
  5043.                             {
  5044.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5045.  
  5046.                                 if(y1 != last)
  5047.                                     line = &plane[(last = y1) * modulo];
  5048.  
  5049.                                 line[x1 >> 3] |= shift[x1 & 7];
  5050.                             }
  5051.                         }
  5052.                         while(xstep < dx);
  5053.                     }
  5054.                     else
  5055.                     {
  5056.                         if(dx == dy)
  5057.                             diff = 0;
  5058.                         else
  5059.                             diff = dy / 2;
  5060.  
  5061.                         do
  5062.                         {
  5063.                             ystep++;
  5064.  
  5065.                             if(diff > 0)
  5066.                                 diff -= dx;
  5067.                             else
  5068.                             {
  5069.                                 xstep++;
  5070.  
  5071.                                 diff = diff + dy - dx;
  5072.                             }
  5073.  
  5074.                             {
  5075.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5076.  
  5077.                                 if(y1 != last)
  5078.                                     line = &plane[(last = y1) * modulo];
  5079.  
  5080.                                 line[x1 >> 3] |= shift[x1 & 7];
  5081.                             }
  5082.                         }
  5083.                         while(ystep < dy);
  5084.                     }
  5085.                 }
  5086.  
  5087.                 if(!pen)
  5088.                 {
  5089.                     if(y1 != last)
  5090.                         line = &plane[(last = y1) * modulo];
  5091.  
  5092.                     line[x1 >> 3] &= masks[x1 & 7];
  5093.                 }
  5094.             }
  5095.             else
  5096.             {
  5097.                 line[x >> 3] &= masks[x & 7];
  5098.  
  5099.                 xstep = ystep = 0;
  5100.  
  5101.                 if(dy < 0)
  5102.                 {
  5103.                     if(dx > -dy)
  5104.                     {
  5105.                         diff = -dx / 2;
  5106.  
  5107.                         do
  5108.                         {
  5109.                             xstep++;
  5110.  
  5111.                             if(diff > 0)
  5112.                             {
  5113.                                 ystep--;
  5114.  
  5115.                                 diff = diff - dy - dx;
  5116.                             }
  5117.                             else
  5118.                                 diff -= dy;
  5119.  
  5120.                             {
  5121.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5122.  
  5123.                                 if(y1 != last)
  5124.                                     line = &plane[(last = y1) * modulo];
  5125.  
  5126.                                 line[x1 >> 3] &= masks[x1 & 7];
  5127.                             }
  5128.                         }
  5129.                         while(xstep < dx);
  5130.                     }
  5131.                     else
  5132.                     {
  5133.                         if(dx == -dy)
  5134.                             diff = 0;
  5135.                         else
  5136.                             diff = -dy / 2;
  5137.  
  5138.                         do
  5139.                         {
  5140.                             ystep--;
  5141.  
  5142.                             if(diff > 0)
  5143.                                 diff -= dx;
  5144.                             else
  5145.                             {
  5146.                                 xstep++;
  5147.  
  5148.                                 diff = diff - dy - dx;
  5149.                             }
  5150.  
  5151.                             {
  5152.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5153.  
  5154.                                 if(y1 != last)
  5155.                                     line = &plane[(last = y1) * modulo];
  5156.  
  5157.                                 line[x1 >> 3] &= masks[x1 & 7];
  5158.                             }
  5159.                         }
  5160.                         while(ystep > dy);
  5161.                     }
  5162.                 }
  5163.                 else
  5164.                 {
  5165.                     if(dx > dy)
  5166.                     {
  5167.                         diff = -dx / 2;
  5168.  
  5169.                         do
  5170.                         {
  5171.                             xstep++;
  5172.  
  5173.                             if(diff > 0)
  5174.                             {
  5175.                                 ystep++;
  5176.  
  5177.                                 diff = diff + dy - dx;
  5178.                             }
  5179.                             else
  5180.                                 diff += dy;
  5181.  
  5182.                             {
  5183.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5184.  
  5185.                                 if(y1 != last)
  5186.                                     line = &plane[(last = y1) * modulo];
  5187.  
  5188.                                 line[x1 >> 3] &= masks[x1 & 7];
  5189.                             }
  5190.                         }
  5191.                         while(xstep < dx);
  5192.                     }
  5193.                     else
  5194.                     {
  5195.                         if(dx == dy)
  5196.                             diff = 0;
  5197.                         else
  5198.                             diff =  dy / 2;
  5199.  
  5200.                         do
  5201.                         {
  5202.                             ystep++;
  5203.  
  5204.                             if(diff > 0)
  5205.                                 diff -= dx;
  5206.                             else
  5207.                             {
  5208.                                 xstep++;
  5209.  
  5210.                                 diff = diff + dy - dx;
  5211.                             }
  5212.  
  5213.                             {
  5214.                                 LONG x1 = x + xstep,y1 = y + ystep;
  5215.  
  5216.                                 if(y1 != last)
  5217.                                     line = &plane[(last = y1) * modulo];
  5218.  
  5219.                                 line[x1 >> 3] &= masks[x1 & 7];
  5220.                             }
  5221.                         }
  5222.                         while(ystep < dy);
  5223.                     }
  5224.                 }
  5225.  
  5226.                 if(pen)
  5227.                 {
  5228.                     if(y1 != last)
  5229.                         line = &plane[(last = y1) * modulo];
  5230.  
  5231.                     line[x1 >> 3] |= pen;
  5232.                 }
  5233.             }
  5234.         }
  5235.     }
  5236.  
  5237.     return(0);
  5238. }
  5239.